zoukankan      html  css  js  c++  java
  • hdu5765 Bonds

    题目链接

    problem

    一个n个点m条边的连通图,如果割掉某个边集这个图不再连通,就称这个边集为割集。如果添加上某个割集中任意一条边图会连通,就称这个割集为最小割集(Bond)。

    求出每条边在多少个Bond中出现过。

    solution

    显然的,割掉一个Bond会把这张图分成两张图。如果一条边所连的两个点分别在这两张新图中,这条边就在这个割集中。发现这个比较难统计。
    正难则反,对于一条边,我们求它所连接的两个点在同一个连通块中时,有多少个合法的Bond。

    我们用二进制来表示一个点集,用(Lim(即2^n-1))表示全集。只有当点集x是个连通块且点集(x)^(Lim)是个连通块时,x可以表示一个Bond。

    这样对于一条边(u,v)。就是求((1<<u)|(1<<v))的超集中bond的数量。(FMT)优化一下即可。复杂度(Theta(n2^n))

    上面某个点集是否是连通块需要预处理一下。我们用(e[i])表示与(i)这个点有连边的点集,(f[i])表示(i)这个集合是否是一个联通块。如果某个点(u)与点集(i)中的点有连边,我们就可以从(f[i])转移到(f[i | (1<<u])了。

    code

    /*
    * @Author: wxyww
    * @Date:   2019-12-15 11:13:24
    * @Last Modified time: 2019-12-15 14:15:05
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 1 << 21;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1; c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0'; c = getchar();
    	}
    	return x * f;
    }
    int e[N];
    int f[N],u[1010],v[1010];
    int main() {
    	for(int T = read(),t = 1;t <= T;++t) {
    		int n = read(),m = read();
    		memset(f,0,sizeof(f));
    		memset(e,0,sizeof(e));
    		for(int i = 1;i <= m;++i) {
    			u[i] = read(),v[i] = read();
    			e[u[i]] |= 1 << v[i];
    			e[v[i]] |= 1 << u[i];
    		}
    		for(int i = 0;i < n;++i) f[1 << i] = 1;
    		int Lim = (1 << n) - 1;
    		for(int i = 0;i <= Lim;++i)
    			if(f[i])	for(int j = 0;j < n;++j) if(e[j] & i) f[i | (1 << j)] = 1;
    		int ans = 0;
    		for(int i = 0;i <= Lim;++i) {
    			f[i] &= f[i ^ Lim];
    			ans += f[i];
    		}
    		ans >>= 1;
    		for(int i = 0;i < n;++i)
    			for(int j = 0;j <= Lim;++j)
    				if(!(j >> i & 1)) f[j] += f[j | (1 << i)];
    		printf("Case #%d:",t);
    		for(int i = 1;i <= m;++i)
    			printf(" %d",ans - f[(1 << u[i]) | (1 << v[i])]);
    		puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    神盾局第4季
    PAT 1053. Path of Equal Weight (30)
    PAT 1052. Linked List Sorting (25)
    PAT 1051. Pop Sequence (25)
    PAT-1049. Counting Ones (30)
    PAT-1047. Student List for Course (25)
    PAT 1045. Favorite Color Stripe (30)
    每日编程-20170308
    技术博客的第一篇文章
    《C语言》while语句和dowhie语句(7)
  • 原文地址:https://www.cnblogs.com/wxyww/p/hdu5765.html
Copyright © 2011-2022 走看看