题意:给出n种距离,设计一个有m个刻度的尺子,使得每个刻度都可以直接量出,要求在m尽量小的情况下尺子的总长度尽量短,第一个必须是0,输出保证m<=7
思路:首先先确定出最小的m,Cm(2)解出可能的最小的m,那么接着开始枚举m,每次得到的一个解都是有给出的n种距离和已有的解的出来的,那么这个解又能得到与之前得出来的解的差和与最大尺度差的两种解,还有几个地方需要减枝,比如解是严格的递增的,还有如果超过最大的尺度那么这个解就是不合格的,回溯处理,还要注意必须是出现的才能用来组成解
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; int n,d[55],ans,a[8]; int cnt[1000005],vis[55]; bool dfs(int u){ if (u == ans){ for (int i = 1; i <= n-1; i++) if (!vis[i]) return 0; return 1; } for (int i = 1; i <= u-1; i++) for (int j = 1; j <= n-1; j++) if (!vis[j]){ int dd = a[i] + d[j]; if (dd <= a[u-1]) continue; if (dd >= d[n]) continue; a[u] = dd; queue<int> q; for (int k = 1; k <= u-1; k++){ dd = a[u] - a[k]; if (cnt[dd] && !vis[cnt[dd]]){ vis[cnt[dd]] = 1; q.push(cnt[dd]); } } dd = d[n] - a[u]; if (cnt[dd] && !vis[cnt[dd]]){ vis[cnt[dd]] = 1; q.push(cnt[dd]); } if (dfs(u+1)) return 1; while (!q.empty()){ vis[q.front()] = 0; q.pop(); } } return 0; } int main(){ int t = 0; while (scanf("%d",&n) != EOF && n){ for (int i = 1; i <= n; i++) scanf("%d",&d[i]); sort(d+1,d+1+n); n = unique(d+1,d+1+n) - d - 1; memset(cnt,0,sizeof(cnt)); for (int i = 1; i <= n; i++) cnt[d[i]] = i; ans = 2; while (ans*(ans-1)/2 < n) ans++; a[1] = 0; memset(vis,0,sizeof(vis)); while (!dfs(2)) ans++; printf("Case %d:\n",++t); printf("%d\n",ans); a[ans] = d[n]; for (int i = 1; i <= ans; i++) printf("%d ",a[i]); puts(""); } return 0; }