题意:
给出n种距离,设计一个有m个刻度的尺子,使得每个刻度都可以直接量出,要求在m尽量小的情况下尺子的总长度尽量短,第一个必须是0,输出保证 m<=7 。
解析:
回溯搜索,先确定下第一个刻度是0,第二个刻度是d[0],用vis数组来记录每个 d[i] 是否被用过,然后枚举 arr[j]+d[i] , arr 数组指的是当前已经选出的刻度,当 arr[j]+d[i]>arr[cnt−1] 时,确定下 arr[cnt]=arr[j]+d[i] ,并标记,同时进入下一层搜索,当前层结束时,还原状态。
注意:
题目有一个坑点,就是尺子最大的刻度不能超过测量的最大刻度,在这边被WA了,看了帆神的题解知道了这个坑点。还有一个剪枝,就是当前选出的刻度超过 m ,就return。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 105;
int m, n, maxlen;
bool vis[N];
int arr[N], scale[N], d[N];
void doit(int cnt) {
for(int i = 0; i < cnt; i++) {
int tmp = arr[cnt] - arr[i];
for(int j = 0; j < n; j++) {
if(!vis[j] && d[j] == tmp) {
vis[j] = true;
}
}
}
}
bool judge() {
for(int i = 0; i < n; i++)
if(!vis[i]) return false;
return true;
}
void dfs(int cnt) {
bool vis2[N];
if(cnt > m || arr[cnt-1] > maxlen) return ;
if(judge()) {
if((cnt < m) || (cnt == m && arr[cnt-1] < maxlen)) {
maxlen = arr[cnt-1];
m = cnt;
memcpy(scale, arr, sizeof(arr));
}
}
memcpy(vis2, vis, sizeof(vis));
for(int i = 0; i < n; i++) {
if(!vis[i]) {
for(int j = 0; j < cnt; j++) {
if(arr[j] + d[i] > arr[cnt-1]) {
arr[cnt] = arr[j] + d[i];
doit(cnt);
dfs(cnt+1);
memcpy(vis, vis2, sizeof(vis));
}
}
}
}
}
void init() {
memset(vis, false, sizeof(vis));
memset(arr, 0, sizeof(arr));
}
int main() {
int cas = 1;
while(scanf("%d", &n) != EOF && n) {
init();
for(int i = 0; i < n; i++)
scanf("%d", &d[i]);
sort(d, d+n);
m = INF, maxlen = d[n-1];
arr[0] = 0, arr[1] = d[0];
doit(1);
dfs(2);
printf("Case %d:\n", cas++);
printf("%d\n", m);
printf("%d", scale[0]);
for(int i = 1; i < m; i++)
printf(" %d", scale[i]);
puts("");
}
return 0;
}