您的位置:首页 > 其它

POJ 2117 Electricity(无向图割点)

2017-08-24 20:03 344 查看
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])
{
//cut 不是关键节点的结点为0
//关键节点记录他的子树数量(桥边的数目)
//对根节点特判 因为他没有父节点 所有如果从根节点断开
//增加的联通量的数量为子树的数量减1
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;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: