hdu3671 Bonnie and Clyde 求割点

/*
    从一个图当中去掉两个节点使得图不联通的方法有多少种
    首先枚举去掉的第一个点,去掉第一个点之后
    1. 图已经不连通且分为两块:
        a.这两块各含一个节点,此时无法通过再去掉一个点使图不连通;
        b.其中一块只含一个节点,另一块有多个节点,此时从含多个结点的块中任取一个搭配去掉的第一个节点,
            共有n - 2 种;
        c.这两块各含多个节点,则从剩下节点中取出任何一个与去掉的第一个节点搭配,共有n - 2种方法;
    2.图已经不连通且分为三块及以上:
        从剩下节点中任取一个,共有n - 1种;
    3.图依旧联通:
        从剩下的点中找割点,方法数加上割点的个数;
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
const int maxn = 1000 + 5;
const int inf = 1000000000;
int vis[maxn],pre[maxn],iscut[maxn];
int low[maxn],num,dfs_clock,cut,n,m;
int v[maxn];
vector<int>G[maxn];
void dfs_count(int u,int fa,int del)//求出去掉某一节点后连通块的个数,看网上标程发现下面求割点的dfs可以顺便求连通块数;
{
    vis[u] = 1;
    ++num;
    for(int i=0;i<G[u].size();i++){
        int v = G[u][i];
        if(vis[v] ||v == fa||v == del)   continue;
        dfs_count(v,u,del);
    }
    return ;
}
int dfs(int u,int fa,int del)                       //寻找割点
{
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;
    for(int i=0;i<G[u].size();i++){
        int v = G[u][i];
        if(v==del)      continue;
        if(!pre[v]){
            ++child;
            int lowv = dfs(v,u,del);
            lowu = min(lowu,lowv);
            if(lowv >= pre[u]){
                iscut[u] = 1;
            }
        }
        else if(pre[v]<pre[u]&&v!=fa){
            lowu = min(lowu,pre[v]);
        }
    }
    if(fa<0&&child==1){
        iscut[u] = 0;
    }
    low[u] = lowu;
    return lowu;
}
int main()
{
    //freopen("D:\\professional debugging\\in5.txt","r",stdin);
    //freopen("D:\\professional debugging\\out52.txt","w",stdout);
    int kase = 1;
    while(scanf("%d %d",&n,&m)==2&&n){   //此题的m可以等于0,一开始&&n&&m就无奈wa了好多发
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
        for(int i=0;i<m;i++){
            int x,y;
            scanf("%d %d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        int ans = 0;
        for(int i=1;i<=n;i++){
            int block = 0;
            mem(vis,0);     mem(v,0);
            for(int j = 1;j<=n;j++){
                if(i==j)    continue;
                if(!vis[j]){
                    num = 0;
                    dfs_count(j,-1,i);
                    v[++block] = num;
                }
            }
            if(block==1){
                mem(low,0);     mem(pre,0);     mem(iscut,0);   dfs_clock = 0;
                cut = 0;
                if(i==1)
                    dfs(2,-1,1);
                else
                    dfs(1,-1,i);
                for(int k=1;k<=n;k++)
                    if(iscut[k])    ++cut;
                ans += cut;
            }
            else if(block==2){
                sort(v+1,v + 1 + block);
                if(v[1]==1&&v[2]!=1)
                    ans += n-2;
                else if(v[1]!=1&&v[2]!=1)
                    ans += n-1;
            }
            else{
                ans += n-1;
            }
        }
        ans /= 2;
        printf("Case %d: %d\n",kase++,ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值