HDU - 4587 TWO NODES 求割點變形(去掉一個割點能得到的最大連通塊數)

題意:給出一張圖,問從中任意去掉兩個點及其鄰接邊,所有可能情況剩下的圖中連通塊的數量最大是多少。

思路:先枚舉去電其中一個點,剩下的一個點用tarjan求無向圖割點類似的方法求個最大值,具體就是當一個點能成爲割點時,我們不是將其標記出來,而是將其計數器+1,最後取一個最大值就行了。

需要注意的就是當根節點爲割點時,將其去掉以後得到的新連通塊數量是son - 1.(son爲搜索樹上其兒子的數量)

這個題逼着我重新理解了一遍tarjan算法求無向圖割邊割點,也算是很有意義了。

代碼:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int> P;
const int MAXN = 5010;
int pre[MAXN], cnt;
int dfn[MAXN], low[MAXN], block[MAXN], tid;
int ban;
struct node{
	int v, next;
	node() {}
	node(int _v, int _next) : v(_v), next(_next) {}
}mp[MAXN << 1];
void init()
{
	memset(pre, -1, sizeof(pre));
	cnt = 0;
}
void add(int u, int v)
{
	mp[cnt] = node(v, pre[u]); pre[u] = cnt++;
	mp[cnt] = node(u, pre[v]); pre[v] = cnt++;
}
void dfs(int u, int fa)
{
	int v, son = 0;
	low[u] = dfn[u] = ++tid;
	for(int i = pre[u]; ~i; i = mp[i].next)
	{
		v = mp[i].v;
		if(v == fa || v == ban) continue;
		if(!dfn[v])
		{
			son++;
			dfs(v, u);
			low[u] = min(low[u], low[v]);
			if(dfn[u] <= low[v])
			block[u]++;
		}
		else if(dfn[v] < low[u]) low[u] = dfn[v];
	}
	if(fa == -1)//注意這裏cut[u]並非等於son
	block[u] = son - 1;
}
int solve(int n)
{
	int ans = 0, tmp;
	for(ban = 0; ban < n; ban++)
	{
		tmp = tid = 0;
		memset(block, 0, sizeof(block));
		memset(dfn, 0, sizeof(dfn));
		for(int i = 0; i < n; i++)
		{
			if(i == ban || dfn[i]) continue;
			dfs(i, -1);
			tmp++;
		}
		for(int i = 0; i < n; i++)
		if(i != ban)
		ans = max(ans, tmp + block[i]);
	}
	return ans;
}
int main()
{
	int n, m, u, v;
	while(~scanf("%d %d", &n, &m))
	{
		init();
		for(int i = 0; i < m; i++)
		{
			scanf("%d %d", &u, &v);
			add(u, v);
		}
		printf("%d\n", solve(n));
	}
 	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章