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 }