题意:给一个20个点无向连通图,求每条边被多少个极小割集包括
分析:极小割集是边的集合,很显然可以知道,极小割集恰好吧原图分成两部分(这个如果不明白可以用反证法)
然后就是奉上官方题解:http://bestcoder.hdu.edu.cn/blog/ 2016多校训练第4场1003
其实大体思路就是每次枚举一种可能的割集,即状压枚举,其中有不合法的,可以通过预处理标记所有的合法状态
剩下的就是贴代码了,好好看代码细节才是最重要的
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <map> #include <queue> #include <vector> using namespace std; typedef long long LL; const int N = (1<<20)+5; int g[N],sum[N],T,kase,n,m,u[205],v[205],tot; bool can[N]; queue<int>q; inline int lowbit(int x){return x&(-x);} int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m),tot=1<<n; memset(g,0,sizeof(g)); memset(can,false,sizeof(can)); memset(sum,0,sizeof(sum)); for(int i=0;i<m;++i){ scanf("%d%d",&u[i],&v[i]); g[1<<u[i]]|=1<<v[i]; g[1<<v[i]]|=1<<u[i]; } for(int i=1;i<tot;++i) g[i]|=g[i-lowbit(i)]|g[lowbit(i)]; for(int i=0;i<n;++i)q.push(1<<i),can[1<<i]=true; while(!q.empty()){ int u=q.front();q.pop(); int go=g[u]^(g[u]&u); while(go){ int to=lowbit(go)|u; if(!can[to])q.push(to),can[to]=true; go-=lowbit(go); } } int all=0; for(int i=1;i<tot;++i){ int j=(tot-1)^i; if(i<j&&can[i]&&can[j]){ ++sum[i];++sum[j];++all; } } for(int j=0;j<n;++j){ for(int i=tot-1;i>0;--i) if(!(i&(1<<j)))sum[i]+=sum[i^(1<<j)]; } printf("Case #%d:",++kase); for(int i=0;i<m;++i) printf(" %d",all-sum[(1<<u[i])|(1<<v[i])]); printf("\n"); } return 0; }
时间: 2024-11-05 02:37:23