POJ 2117 Electricity(无向图割点)

POJ 2117 Electricity(无向图割点)

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

题意:

        给你一个无向图(不一定连通),现在问你从该图中删除任意一个顶点之后,该无向图所具有的连通分量数目最大是多少?

分析:

        本题与前一题不一样,前一题是要你判定哪些点是割点。但是这题需要你求出割点到底能割出几个连通分量。本题的无向图可能不连通。我们只需要考虑在同一个连通分量时,一个割点到底能把图割成几部分即可。

        在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.

        (以上含义需仔细体会验证)

AC代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=10000+10;
int n,m;
vector<int> G[maxn];
int cut[maxn];
int low[maxn];
int pre[maxn];
int dfs_clock;
int tarjan(int u,int fa)
{
    int lowu= pre[u]=++dfs_clock;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!pre[v])
        {
            int lowv=tarjan(v,u);
            lowu=min(lowv,lowu);
            if(lowv>=pre[u]) cut[u]++;
        }
        else if(pre[v]<pre[u] && v!=fa)
            lowu = min(lowu,pre[v]);
    }
    return low[u]=lowu;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2&&n)
    {
        dfs_clock=0;
        memset(cut,0,sizeof(cut));
        memset(pre,0,sizeof(pre));
        for(int i=0;i<n;i++) G[i].clear();
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        int sum=0;//计数连通分量数目
        int max_cut=-10000;
        for(int i=0;i<n;i++)if(!pre[i])
        {
            sum++;
            tarjan(i,-1);
            cut[i]--;
        }
        for(int i=0;i<n;i++)
            max_cut=max(max_cut,cut[i]);
        printf("%d\n",sum+max_cut);
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值