HDU5765 Bonds 最小割极

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 }
原文地址:https://www.cnblogs.com/ITUPC/p/5728468.html