http://acm.hdu.edu.cn/showproblem.php?pid=5765
题意:无向连通图,问每条边在几个最小割极上
思路:用位压形式,表示边的关系。g[1<<i]=1<<x 表示第i个点与哪几个点相连。然后,处理出每种点集和哪些点相连。每个点构成一个连通图,所以枚举当前点集,可以得到所有连通图的点集,计算出数量,用高维前缀和处理所有包含i点的连通块
ans=(所有连通块-同时包含(i,j)的连通块数目)/2 应为以(i,j)为割边的连通块,删除该边以后,数量加倍,所以除2
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<set> 7 #include<map> 8 #include<vector> 9 #include<cstring> 10 #include<stack> 11 #include<cmath> 12 #include<queue> 13 #include <conio.h> 14 #define clc(a,b) memset(a,b,sizeof(a)) 15 #include <bits/stdc++.h> 16 const int maxn = 20005; 17 const int inf=0x3f3f3f3f; 18 const double pi=acos(-1); 19 typedef long long LL; 20 using namespace std; 21 //const LL MOD = 1e9+7; 22 void fre(){freopen("in.txt","r",stdin);} 23 inline int lb(int x){return x&(-x);} 24 const int N=1<<21; 25 26 int g[N],a[N],u[500],v[500]; 27 bool vis[N]; 28 int sum[N]; 29 int main(){ 30 int T; 31 scanf("%d",&T); 32 for(int cas=1;cas<=T;cas++){ 33 int n,m; 34 scanf("%d%d",&n,&m); 35 for(int i=1;i<1<<n;i++) sum[i]=0,g[i]=0,vis[i]=false; 36 for(int i=0;i<m;i++){ 37 int x,y; 38 scanf("%d%d",&x,&y); 39 u[i]=x,v[i]=y; 40 g[1<<x]|=1<<y; 41 g[1<<y]|=1<<x; 42 } 43 for(int i=1;i<1<<n;i++) g[i]|=g[i-lb(i)]|g[lb(i)]; 44 int l=0,r=0; 45 for(int i=0;i<n;i++) vis[a[r++]=1<<i]=true; 46 while(l<r){ 47 int c=a[l++]; 48 int res=g[c]^(g[c]&c); 49 while(res){ 50 int tem=lb(res)|c; 51 if(!vis[tem]) vis[a[r++]=tem]=true; 52 res-=lb(res); 53 } 54 } 55 int all=0; 56 for(int i=1;i<1<<n;i++){ 57 int j=(1<<n)-1; 58 j^=i; 59 if(vis[i]&&vis[j]){ 60 sum[i]++,sum[j]++,all++; 61 } 62 } 63 for(int j=0;j<n;j++){ 64 for(int i=(1<<n)-1;i>=1;i--) 65 if(!(i&(1<<j))) sum[i]+=sum[i^(1<<j)]; 66 } 67 printf("Case #%d: ",cas); 68 for(int i=0;i<m;i++){ 69 printf("%d",(all-sum[(1<<u[i])|(1<<v[i])])/2); 70 if(i==m-1) cout<<endl; 71 else cout<<" "; 72 } 73 } 74 return 0; 75 76 }