poj2117 Electricity

 

 
试题描述
求一个图删除一个点之后,联通块最多有多少。
输入
多组数据。第一行两个整数 P,C 表示点数和边数。
接下来 C 行每行两个整数 p1,p2,表示 p1 与 p2 有边连接,保证无重边。读入以 0 0 结束。
输出
输出若干行,表示每组数据的结果。
输入示例
3 3
0 1
0 2
2 1
4 2
0 1
2 3
3 1
1 0
0 0
输出示例
1
2
2

详解参考https://blog.csdn.net/u013480600/article/details/30976823。

在dfs的时候,我们用cut[i]==X表示在dfs树中当i节点被删除时,i节点的X个儿子被切割开来(可以认为cut[i]是i节点与它的儿子连接的桥边的数目)。注意:如果i是根且其儿子只有1个,虽然i不是割点,cut[i]依然=1。如果i节点非割点,那么cut[i]=0。如果i是割点,那么cut[i]就是i被删除后将割出来的儿子数目。

       然后我们求出了每个点的cut[i]值,即i点被删除,会有cut[i]个儿子树被割出来。如果i是dfs树的非根节点,那么cut[i]== 切除i之后增加的连通分量数目。如果i是dfs树的根节点,那么cut[i]-1才是切除i之后增加的连通分量数目(想想是不是)。

        如果原始cut[i]=0,表示i是孤立的一点,此时cut[i]-1=-1.

        如果原始cut[i]=1,表示i为根且有一个儿子,此时cut[i]-1=0.

        如果原始cut[i]>=2,表示i为根且分割了>=2个儿子,此时cut[i]-1>=1.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#define MAXN 100010
#define REP(i,k,n) for(int i=k;i<=n;i++)
#define in(a) a=read()
using namespace std;
inline int read(){
    int f=1,x=0;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,m,cnt,ans;
int total=0,head[MAXN],to[MAXN<<2],nxt[MAXN<<2];
int dfn[MAXN],low[MAXN],sum[MAXN];
inline void adl(int a,int b){
    total++;
    to[total]=b;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void tarjan(int u,int f){
    low[u]=dfn[u]=++cnt;
    for(int e=head[u];e;e=nxt[e]){
        if(!dfn[to[e]]){
            tarjan(to[e],u);
            low[u]=min(low[to[e]],low[u]);
            if(low[to[e]]>=dfn[u]) sum[u]++;
        }
        else if(to[e]!=f)  low[u]=min(low[u],dfn[to[e]]);
    } 
    return ;
}
int main(){
    while(scanf("%d%d",&n,&m)){
        if(n==0 && m==0)  return 0;
        int a,b;
        total=cnt=ans=0;
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(head));
        memset(low,0,sizeof(low));
        memset(sum,0,sizeof(sum));
        REP(i,1,m){
            in(a);in(b);
            adl(a,b);
            adl(b,a);    
        }
        int num=0;
        ans=-10000;
        REP(i,0,n-1)
            if(!dfn[i]){
                num++; 
                tarjan(i,-1);
                sum[i]--;
            }
        REP(i,0,n-1) ans=max(ans,sum[i]);
        cout<<ans+num<<endl;
    }
    return 0;
}

 

posted @ 2018-09-26 13:28  Dijkstra·Liu  阅读(558)  评论(1编辑  收藏  举报