题意:N个人,每个人都有一些认识的人,现在要求把这些人分成两堆,两堆人数差不超过1,然后要让两堆人两两认识,没两个人认识需要花费1分钟,要使得总花费时间最少,问方案。
思路:每种情况的花费时间,肯定取决于那个对于分到的一堆人里面,不认识的人最多的那个人,然后利用位运算去记录每个人认识的人,还是利用位运算去枚举两堆的情况。搜索所有答案。加了几个时间才勉强跑过。
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define max(a,b) ((a)>(b)?(a):(b)) #define INF 0x3f3f3f3f const int N = 30; int n, m, a, b, know[N], ans, s; inline int bitcount(int x) { return x == 0 ? 0 : (bitcount(x/2) + (x&1)); } inline int cal(int s, int Min, int s1) { int ans = 0; int ss = (((1<<n) - 1)^s); int s2 = n - s1; if (abs(s1 - s2) > 1) return -1; for (int i = 0; i < n; i++) { if (s&(1<<i)) { int kno = (know[i]&s); int lone = s1 - bitcount(kno); ans = max(ans, lone); } if (ss&(1<<i)) { int kno = (know[i]&ss); int lone = s2 - bitcount(kno); ans = max(ans, lone); } if (ans > Min) return -1;//剪枝 } return ans; } void dfs(int num, int ss, int d) { if ((n - d) + num < n / 2) return;//剪枝 if (num >= n / 2) { int t = cal(ss, ans, num); if (t != -1) { if (ans > t) { ans = t; s = ss; } } return; } dfs(num + 1, ss|(1<<d), d + 1); dfs(num, ss, d + 1); } inline void solve() { ans = INF; int i; dfs(0, 0, 0); printf("%d\n", ans); printf("%d", bitcount(s)); for (i = 0; i < n; i++) if (s&(1<<i)) printf(" %d", i + 1); printf("\n"); int ss = (((1<<n) - 1)^s); printf("%d", bitcount(ss)); for (i = 0; i < n; i++) if (ss&(1<<i)) printf(" %d", i + 1); printf("\n"); } int main() { int bo = 0; while (~scanf("%d", &n)) { if (bo++) printf("\n"); for (int i = 0; i < n; i++) { scanf("%d%d", &a, &m); a--; know[a] = (1<<a); while (m--) { scanf("%d", &b); b--; know[a] = (know[a] | (1<<b)); } } solve(); } return 0; }
UVA 649 - You Who?(搜索+位运算+剪枝),布布扣,bubuko.com
原文:http://blog.csdn.net/accelerator_/article/details/22990113