• 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
    "
    #define in64 "%I64d"
    #else
    #define i64 long long
    #define out64 "%lld
    "
    #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;
    }
    
     


  • 相关阅读:
    STL-- vector中resize()和reserve()区别
    计算机网络--网络层
    计算机网络--数据链路层
    算法--排序算法
    数据结构--树--哈夫曼树
    数据结构--树--AVL树
    数据结构--树--二叉查找树
    数据结构--树--红黑树
    深入理解计算机系统读书笔记
    C++面试笔记--字符串
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5206026.html
Copyright © 2020-2023  润新知