HDU 4587 TWO NODES(无向图割点)

HDU 4587 TWO NODES(无向图割点)

http://acm.hdu.edu.cn/showproblem.php?pid=4587

题意:

        给你一个无向图,问你从这个无向图中删除任意两个点之后所能获得的独立连通分量个数的最大值.

分析:

        首先我们从0到n-1枚举需要删除的第一个点u,然后在这个G-u的新图中,我们剩下要删除的第二个点应该尽量为割点.(如果图中无割点,那也没办法了).

        下面我们来处理G-u这个余图.我们令cut[i]表示删除i节点之后整个图的连通分量会在原来基础上增加cut[i]个.

        首先对于非根节点i来说,如果i不是割点,那么cut[i]=0;如果i是割点,cut[i]=DFS树中i节点的儿子数.

        其次对于根节点i来说,如果i在DFS树中儿子为0,那么cut[i]=-1.否则cut[i]=DFS树中i的儿子数-1.

        最终在删除u节点后,我们只要对于pre[i]=0的每个节点(除了u)求一次tarjan(),就可以得出删除u的连通分量数目sum和每个cut[i].然后我们在通过求max(sum+cut[i]) 得出最优解.(这个比较抽象,还是看代码吧)

总结一句:就是(删除点u后的连通分量数量)加上(在删除u的的无向图上删除v后增加的连通分量);

AC代码:

#include<cstring>
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=5000+5;
int n,m;
vector<int>G[maxn];
int dfs_clock;
int pre[maxn],cut[maxn],low[maxn];
int tarjan(int u,int fa,int forbid)//某个点被删除不能选
{
	int lowu=pre[u]=++dfs_clock;
	int child=0;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa||v==forbid)continue;
		if(!pre[v])
		{
			child++;
			int lowv=tarjan(v,u,forbid);
			lowu=min(lowu,lowv);
			if(lowv>=pre[u])
			{
				cut[u]++;
			}
		}
		else
		{
			lowu=min(lowu,pre[v]);
		}
	}
	if(fa<0)
		cut[u]--;
	//cut记录的是删除掉点u可以增加多少联通量
	return low[u]=lowu;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		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 ans=-100;
		for(int u=0;u<n;u++)//删除u
		{
			int sum=0;//删除u后的 连通分量
			dfs_clock=0;
			memset(pre,0,sizeof pre);
			memset(cut,0,sizeof cut);
			for(int v=0;v<n;v++)
			{
				if(v!=u&&!pre[v])
				{
					sum++;
					tarjan(v,-1,u);
				}

			}
			for(int v=0;v<n;v++)
			{
				if(v!=u)
				{
					ans=max(ans,sum+cut[v]);
				}
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值