POJ 2117 Electricity 双联通分量 割点

http://poj.org/problem?id=2117 

这个妹妹我竟然到现在才见过,我真是太菜了~~~

求去掉一个点后图中最多有多少个连通块。(原图可以本身就有多个连通块)

首先设点i去掉后它的子树(我知道不准确但是领会精神就好了吧orz)能分成cut[i]个连通块,那么除了节点之外去掉任意一个点就多出cut[i]个联通块(根节点多出cut[i]-1个连通块)。

(简洁的语言说cut[i]表示的就是i点是多少个点双连通分量的割顶,我连割顶都忘了是什么了嘤嘤嘤)

每个点只遍历一次且一定在所在连通块(子树)被割点切割时被遍历,遍历过之后判断这个子节点是否从割点被切割( low[y]>=x )就得到cut了。

注意cut[i]可以为负,当一个点单独作为连通块时它的cut[i]就是-1。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 #define LL long long
 9 #define pa pair<int,int>
10 const int maxn=10010;
11 const LL minf=(LL)5e17;
12 int n,m;
13 struct nod{
14     int x,y,next;
15 }e[maxn*20];
16 int head[maxn]={},tot=1;
17 int dfn[maxn]={},low[maxn]={},cut[maxn]={},cnt=0;
18 inline void init(int x,int y){
19     e[++tot].y=y;e[tot].next=head[x];head[x]=tot;
20 }
21 void dfs(int x,int p){
22     dfn[x]=low[x]=++cnt;
23     for(int i=head[x];i;i=e[i].next){
24         if(!dfn[e[i].y]){
25             dfs(e[i].y,x);
26             low[x]=min(low[x],low[e[i].y]);
27             if(low[e[i].y]>=dfn[x])++cut[x];
28         }
29         else low[x]=min(dfn[e[i].y],low[x]);
30     }
31 }
32 int main(){
33     while(~scanf("%d%d",&n,&m)){
34         if(n==0&&m==0)break;
35         int x,y;tot=0;
36         memset(head,0,sizeof(head));
37         memset(dfn,0,sizeof(dfn));
38         memset(cut,0,sizeof(cut));
39         for(int i=1;i<=m;i++){
40             scanf("%d%d",&x,&y);++x;++y;
41             init(x,y);init(y,x);
42         }
43         int ans=0,ff=-10000;
44         for(int i=1;i<=n;i++)if(!dfn[i]){dfs(i,0);cut[i]--;ans++;}
45         for(int i=1;i<=n;i++)ff=max(ff,cut[i]);
46         printf("%d
",ans+ff);
47     }
48     return 0;
49 }
View Code

原文地址:https://www.cnblogs.com/137shoebills/p/9062435.html