7.13 BHDU 3671 Boonie and Clyde

来源:互联网 发布:好听音乐网络歌曲 编辑:程序博客网 时间:2024/06/10 08:01

题意:求无向图的割点对(即割掉这两个点使得图被分为2个部分)的数量。

思路:枚举第一个点,若该点不是割点,剩下的图就可以用tarjan算存在多少割点。如果第一个点已经是割点,则还有3种情况,该割点分割两个区域且有一个区域只存在1个点,此时新点不能落在只有1个点的区域上,情况数要减1。若该割点分割两个区域且两个区域都只存在1个点,则无割点对。最后就是普遍情况,此时第二个点落在任意位置都能满足题目条件,情况数加上剩余点数。

代码:

#include <iostream>#include <cstring>#include <cstdio>#include <vector>using namespace std;vector<int> adj[1001];int dfn[1001],low[1001],iscut[1001];int cnt,n,m,nv,amt,root,cut,kase=1;void tarjan(int u,int fa){    dfn[u]=low[u]=++cnt;    amt++;    for(int i=0;i<adj[u].size();i++){        int v=adj[u][i];        if(v==nv||v==fa) continue;        if(!dfn[v]){            tarjan(v,u);            low[u]=min(low[u],low[v]);            if(fa == -1){root++;continue;}//统计根节点子树个数,只要子树个数大于1,cut边++            if(dfn[u]<=low[v]){                if(!iscut[u]){iscut[u]=1;cut++;}            }        }        else low[u]=min(low[u],dfn[v]);    }}int main(){    while(~scanf("%d%d",&n,&m)&&(n||m)){        cnt=0;        for(int i=1;i<=n;i++)            adj[i].clear();        for(int i=0;i<m;i++){            int u,v;            scanf("%d%d",&u,&v);            adj[u].push_back(v);            adj[v].push_back(u);        }        int ans=0;        for(nv=1;nv<=n;nv++){            memset(dfn,0,sizeof(dfn));            memset(low,0,sizeof(low));            memset(iscut,0,sizeof(iscut));            int solo=0;            cut=0;            int block=0;            for(int i=1;i<=n;i++)if(i!=nv&&!dfn[i]){                block++;                amt=root=0;                tarjan(i,-1);                if(amt==1) solo++;                if(root>1) {iscut[i] = 1; cut++;}            }            if(block>=3) ans+=n-1;            else if(block==2 && solo==1) ans+=n-2;//solo等于2不加.            else if(block==2 && solo==0) ans+=n-1;            else if(block==1) ans+=cut;        }        printf("Case %d: %d\n",kase++,ans/2);    }    return 0;}

0 0
原创粉丝点击