http://acm.hdu.edu.cn/showproblem.php?pid=5917
即世界上任意6个人中,总有3个人相互认识,或互相皆不认识。
所以子集 >= 6的一定是合法的。
然后总的子集数目是2^n,减去不合法的,暴力枚举即可。
选了1个肯定不合法,2个也是,3个的话C(n, 3)枚举判断,C(n, 4), C(n, 5)
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 50 + 20; int e[maxn][maxn]; const LL MOD = 1e9 + 7; void add(LL &x, LL y) { x = (x + MOD + y) % MOD; } bool ok(int i, int j, int k) { return ((e[i][j] && e[j][k] && e[k][i]) || (!e[i][j] && !e[j][k] && !e[k][i])); } LL po[maxn]; int f; void work() { memset(e, false, sizeof e); int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; ++i) { int u, v; scanf("%d%d", &u, &v); e[u][v] = e[v][u] = 1; } LL ans = po[n]; add(ans, -(n + 1)); add(ans, -(n * (n - 1) / 2)); LL t = 0; for (int i = 1; i <= n; ++i) { for (int j = i + 1; j <= n; ++j) { for (int k = j + 1; k <= n; ++k) { if (!ok(i, j, k)) t++; } } } for (int i = 1; i <= n; ++i) { for (int j = i + 1; j <= n; ++j) { for (int k = j + 1; k <= n; ++k) { for (int h = k + 1; h <= n; ++h) { if (!ok(i, j, k) && !ok(i, j, h) && !ok(i, k, h) && !ok(j, k, h)) t++; } } } } for (int i = 1; i <= n; ++i) { for (int j = i + 1; j <= n; ++j) { for (int k = j + 1; k <= n; ++k) { for (int h = k + 1; h <= n; ++h) { for (int ha = h + 1; ha <= n; ++ha) { if (!ok(i, j, k) && !ok(i, j, h) && !ok(i, k, h) && !ok(j, k, h) && !ok(i, j, ha) && !ok(i, k, ha) && !ok(i, h, ha) && !ok(j, k, ha) && !ok(j, h, ha) && !ok(k, h, ha)) t++; } } } } } t %= MOD; add(ans, -t); printf("Case #%d: %lld ", ++f, ans); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif po[0] = 1; for (int i = 1; i <= maxn - 2; ++i) { po[i] = 2 * po[i - 1] % MOD; } int t; scanf("%d", &t); while (t--) work(); return 0; }