HDU 5765 Bonds 巧妙状压暴力

题意:给一个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;
}
View Code

 

posted @ 2016-07-30 18:57  shuguangzw  阅读(225)  评论(0编辑  收藏  举报