NKOJ4772 串珠子 状压dp
题面:铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子。现在铭铭想用绳子把所有的珠子连接成一个整体。
现在已知所有珠子互不相同,用整数1到n编号。对于第i个珠子和第j个珠子,可以选择不用绳子连接,或者在ci,j根不同颜色的绳子中选择一根将它们连接。如果把珠子看作点,把绳子看作边,将所有珠子连成一个整体即为所有点构成一个连通图。特别地,珠子不能和自己连接。
铭铭希望知道总共有多少种不同的方案将所有珠子连成一个整体。由于答案可能很大,因此只需输出答案对1000000007取模的结果。
解法:f[i]是合法方案总数,g[i]是所有方案总数,只需将所有方案总数减去合法方案总数即为答案。
#include <bits/stdc++.h> using namespace std; #define ll long long const ll mod = 1e9 + 7; ll c[25][25], f[(1 << 16) + 1], g[(1 << 16) + 1]; main() { ll n; scanf("%lld", &n); for (ll i = 1; i <= n; i++) { for (ll j = 1; j <= n; j++) { scanf("%lld", &c[i][j]); } } ll tot = (1 << n) - 1; for (ll s = 1; s <= tot; s++) { g[s] = 1; for (ll i = 1; i <= n; i++) { if (s & (1 << i - 1)) { for (ll j = i + 1; j <= n; j++) if (s & (1 << j - 1)) g[s] = (g[s] * (c[i][j] + 1)) % mod; } } } for (ll s = 1; s <= tot; s++) { for (ll i = s & (s - 1); i; i = s & (i - 1)) { if (!((i ^ s) & (s & -s))) f[s] = (f[s] + f[i] * g[i ^ s]) % mod; } f[s] = ((g[s] - f[s]) % mod + mod) % mod; } printf("%lld", f[tot]); }

浙公网安备 33010602011771号