Hdu 5765 Bonds(高维前缀和)

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值