题目中每个团体加入或不加入联盟一共有2^20种可能性,数据规模很小,直接枚举即可:
#include <stdio.h>
int main()
{
int test, i, k, limit, mask, sum;
int N, arr[20], cnt[20], threshold;
scanf("%d", &test);
while(test--){
threshold = 0;
scanf("%d", &N);
for(i = 0; i < N; ++i){
scanf("%d", &arr[i]);
threshold += arr[i];
cnt[i] = 0;
}
threshold = threshold / 2 + 1;
for(k = 1, limit = 1 << N; k < limit; ++k){
sum = 0;
for(i = 0; (mask = 1 << i) <= k; ++i){
if(k & mask) sum += arr[i];
}
if(sum < threshold) continue;
for(i = 0; (mask = 1 << i) <= k; ++i){
if((k & mask) && sum - arr[i] < threshold) ++cnt[i];
}
}
printf("%d", cnt[0]);
for(i = 1; i < N; ++i) printf(" %d", cnt[i]);
puts("");
}
return 0;
}
用DFS代替手动枚举还可以写成:
#include <stdio.h>
int N, arr[20], cnt[20], threshold;
int stack[20], size;
void dfs(int i, int sum)
{
if(i < 0){
if(sum >= threshold){
int k = 0;
for(; k < size; ++k){
if(sum - arr[stack[k]] < threshold) ++cnt[stack[k]];
}
}
return;
}
dfs(i - 1, sum);
stack[size++] = i;
dfs(i - 1, sum + arr[i]);
--size;
}
int main()
{
int test, i;
scanf("%d", &test);
while(test--){
threshold = 0;
scanf("%d", &N);
for(i = 0; i < N; ++i){
scanf("%d", &arr[i]);
threshold += arr[i];
cnt[i] = 0;
}
threshold = threshold / 2 + 1;
size = 0;
dfs(N-1, 0);
printf("%d", cnt[0]);
for(i = 1; i < N; ++i) printf(" %d", cnt[i]);
puts("");
}
return 0;
}
上面不加剪枝的DFS和枚举实际上都是遍历所有的可能性,但从结果上来看,DFS还是快一些,毕竟枚举的时候每次都还要扫描2遍全部团体是否加入,而DFS时已经将这一信息记录下来了