您的位置:首页 > 其它

Hdu 5765 Bonds(高维前缀和)

2016-10-24 21:02 246 查看
题意:

给一个n个点的无向连通图,求每条边被多少个极小割边集包括 (n<=20,m<=n*(n-1)/2)

思路:

极小边->分成两个联通块

1.先求出与每个状态相邻的点的状态集

2.bfs判断哪些点可以组成一个联通块

3.高维前缀和

#include<bits/stdc++.h>
using namespace std;
const int N=21;
int ans[1<<21],sta[1<<21],x[400],y[400];
bool flag[1<<21];
int q[1<<21];

int lowbit(int x){
return x&-x;
}

int main(){
int _,n,m,u,v;
scanf("%d",&_);
for(int Case=1;Case<=_;Case++){
scanf("%d%d",&n,&m);
for(int i=0;i<(1<<n);i++)   ans[i]=0,flag[i]=false,sta[i]=0;
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
x[i]=u,y[i]=v;
sta[1<<u]|=(1<<v),sta[1<<v]|=(1<<u);
}
//求出与每个状态相邻的点的状态集
for(int i=1;i<(1<<n);i++)
sta[i]=sta[i-lowbit(i)]|sta[lowbit(i)];
int head=0,tail=0,Sta=(1<<n)-1;
for(int i=0;i<n;i++)    q[++tail]=(1<<i),flag[1<<i]=true;
while(head<tail){
int num=q[++head];
//找出其它的点与num相连,而且不被包含在num中
int remain=sta[num]^(sta[num]&num);
while(remain){
int x=lowbit(remain);//只包含一个1
if(!flag[num|x])    flag[num|x]=true,q[++tail]=num|x;
remain-=lowbit(remain);
}
}
int tot=0;
for(int i=1;i<(1<<n);i++)
if(flag[i]&&flag[Sta-i])
ans[Sta-i]++,ans[i]++,tot++;
for(int i=0;i<n;i++)
for(int j=(1<<n)-1;j>=0;j--)
if(!(j>>i&1))   ans[j]+=ans[j^(1<<i)];
printf("Case #%d:",Case);
for(int i=0;i<m;i++)
printf(" %d",(tot-ans[(1<<x[i])|(1<<y[i])])/2);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: