hdu 4997 Biconnected
这题主要是计算连通子图的个数(c)和不连通子图的个数(dc)还有连通度为1的子图的个数(c1)和连通度为2以上的子图的个数(c2)之间的转化关系
主要思路大概例如以下:
用状态压缩的方法算出状态为x的子图的不连通子图个数dc[x],dc[x] = ∑ c[i]*(2^edge[x-i]),i为x的子集且i中有x的编号最小的元素。edge[x] 表示x集合内有几条边
连通子图个数c[x] = 2^edge[x] - dc[x]
想得到双连通子图的个数就要计算单连通子图的个数
单连通子图缩块后是一棵树,假设每次我们选择标号最小的点所在的块为根节点(块)
那么单连通子图能够看成是在这个双连通的根节点(块)的基础上连接一个连通分量。这样能枚举到全部的情况,也不会反复
mc[s][x] += mc[s][x - y] * c[y] * e[s][y]。当中mc[s][x-y]是指把x-y连接到s的方法数,e[s][y]是指s到y的边数
c1[s] += mc[x][s - x],c1[s]是s中单连通子图的个数
而双连通子图个数 c2[s] = c[s] - c1[s]
最后转回去计算mc[s][0]。意思假设根节点s(块)不拓展连通分量的方法数,就相当于计算根节点(块)为双连通子图的方法数。等于c2[s]
再通过这些值计算mc[s+1][?]的值,不断的往上递推来完毕所有的计算
#pragma comment(linker, "/STACK:102400000,102400000") #include<iostream> #include<vector> #include<algorithm> #include<cstdio> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<cmath> #include<cassert> #include<cstring> #include<iomanip> using namespace std; #ifdef _WIN32 #define i64 __int64 #define out64 "%I64d\n" #define in64 "%I64d" #else #define i64 long long #define out64 "%lld\n" #define in64 "%lld" #endif /************ for topcoder by zz1215 *******************/ #define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++) #define FOR(i,a,b) for( int i = (a) ; i <= (b) ; i ++) #define FF(i,a) for( int i = 0 ; i < (a) ; i ++) #define FFD(i,a,b) for( int i = (a) ; i >= (b) ; i --) #define S64(a) scanf(in64,&a) #define SS(a) scanf("%d",&a) #define LL(a) ((a)<<1) #define RR(a) (((a)<<1)+1) #define pb push_back #define pf push_front #define X first #define Y second #define CL(Q) while(!Q.empty())Q.pop() #define MM(name,what) memset(name,what,sizeof(name)) #define MC(a,b) memcpy(a,b,sizeof(b)) #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b)) #define read freopen("out.txt","r",stdin) #define write freopen("out2.txt","w",stdout) const int inf = 0x3f3f3f3f; const i64 inf64 = 0x3f3f3f3f3f3f3f3fLL; const double oo = 10e9; const double eps = 10e-9; const double pi = acos(-1.0); const int mod = 1000000007; const int maxn = 1 << 10; int n, m; int a[10][10]; i64 pow2[maxn]; i64 edge[maxn]; i64 ex[10][maxn]; i64 e[maxn][maxn]; i64 dc[maxn]; i64 c[maxn]; i64 c1[maxn]; i64 c2[maxn]; i64 mc[maxn][maxn]; vector<int>vx; vector<int>v; vector<int>v2; void start(){ MM(edge, 0); MM(dc, 0); MM(c, 0); MM(c1, 0); MM(c2, 0); MM(e, 0); MM(ex, 0); MM(mc, 0); for (int x = 0; x < n; x++){ for (int s = 0; s < (1 << n); s++){ for (int i = 0; i < n; i++)if (s&(1 << i)){ if (!a[x][i]){ ex[x][s] ++; } } } } for (int s = 0; s < (1<<n); s++){ for (int x = 0; x < (1 << n); x++){ for (int i = 0; i < n; i++)if(s&(1<<i)){ e[s][x] += ex[i][x]; } } } for (int s = 1;s < (1 << n); s++){ for (int i = 0; i < n; i++) if(s & (1<<i)){ for (int j = i + 1; j < n; j++) if(s& (1<<j)){ if (!a[i][j]){ edge[s]++; } } } } int head; for (int s = 1; s < (1 << n); s++){ v.clear(); for (int i = 0; i < n; i++){ if (s & (1 << i)){ v.push_back((1<<i)); } } head = v[0]; v.erase(v.begin()); int x; for (int i = 0; i < (1 << ((int)v.size())); i++){ x = 0; for (int pos = 0; pos < v.size(); pos++){ if (i &(1 << pos)) { x += v[pos]; } } x += head; if (x != s){ dc[s] += c[x] * pow2[edge[s - x]]; dc[s] %= mod; } } c[s] = pow2[edge[s]] - dc[s] + mod; c[s] %= mod; } for (int s = 1; s < (1 << n); s++){ vx.clear(); v.clear(); int x; for (int i = 0; i < n; i++){ if (s & (1 << i)){ vx.push_back(1<<i); } } int vxhead = vx[0]; vx.erase(vx.begin()); for (int i = 0; i < (1 << ((int)vx.size())); i++){ x = 0; for (int pos = 0; pos < vx.size(); pos++){ if (i&(1 << pos)){ x += vx[pos]; } } x += vxhead; if (x != s){ c1[s] += mc[x][s - x]; c1[s] %= mod; } } c2[s] = (c[s] - c1[s]+mod)%mod; mc[s][0] = c2[s]; for (int i = 0; i < n; i++){ if (s&(1 << i)){ head = i; break; } } for (int i = head + 1; i < n; i++){ if (!(s&(1 << i))){ v.push_back(1<<i); } } for (int i = 1; i < (1 << ((int)v.size())); i++){ x = 0; for (int pos = 0; pos < v.size(); pos++){ if (i&(1 << pos)){ x += v[pos]; } } v2.clear(); for (int u = 0; u < n; u++){ if (x&(1 << u)){ v2.push_back(1 << u); } } int y; for (int j = 1; j < (1 << ((int)v2.size())); j++) if(j&1){ y = 0; for (int pos = 0; pos < v2.size(); pos++){ if (j & (1 << pos)){ y += v2[pos]; } } mc[s][x] +=(( mc[s][x - y] * c[y])%mod) * e[s][y]; mc[s][x] %= mod; } } } } int main(){ pow2[0] = 1; for (int i = 1; i < maxn; i++){ pow2[i] = pow2[i - 1] * 2; pow2[i] %= mod; } int T; cin >> T; while (T--){ cin >> n >> m; MM(a, 0); int x, y; for (int i = 0; i < n; i++){ a[i][i] = 1; } for (int i = 1; i <= m; i++){ cin >> x >> y; x--; y--; a[x][y] = a[y][x] = 1; } start(); cout << c2[(1 << n) - 1] << endl; } return 0; }