hdu 5631 Rikka with Graph(無向圖的割邊)

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5631

解題思路:

這題要求刪除邊,使得無向圖繼續連通。

由於n個節點只有n+1條邊,所以要麼刪除一條邊,要麼刪除兩條邊。

數據量比較小,可以枚舉要刪除的邊即可。

刪除一條邊很簡單,關鍵是怎麼刪除兩條邊。這裏提供一個用圖論的方法解決。

假設我們先枚舉刪除的兩條邊中的一條,那麼要在剩下的圖當中再找一條邊。到底要刪哪一條呢?反正不能是割邊對吧,原因你懂的。

那麼這個問題轉化爲求割邊數量了。。。剩下的邊減去割邊就是可以再刪掉的一條邊。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;

const int maxn = 105;
struct Edge
{
	int u,v;
}edge[maxn];
int n,ans,sum,map[maxn][maxn];
int dfsn[maxn],Index,low[maxn];
bool cut[maxn][maxn];

void Tarjan(int u,int fa)
{
	dfsn[u] = low[u] = ++Index;
	for(int i = 1; i <= n; i++)
	{
		if(map[u][i] == 0 || i == fa) continue;
		if(dfsn[i] == 0)
		{
			Tarjan(i,u);
			low[u] = min(low[u],low[i]);
			if(low[i] > dfsn[u] && map[u][i] == 1)
				cut[u][i] = cut[i][u] = true;
		}
		else low[u] = min(low[u],dfsn[i]);
	}
}

void solve()
{
	Index = 0;
	memset(dfsn,0,sizeof(dfsn));
	memset(cut,false,sizeof(cut));
	Tarjan(1,0);
	for(int i = 1; i <= n; i++)
		if(dfsn[i] == 0) //去掉一條邊後不連通
		{
			sum--;
			return;
		}
	int cnt = 0; //割邊數量
	for(int i = 1; i <= n; i++)
		for(int j = i + 1; j <= n; j++)
			if(cut[i][j] == true)
				cnt++;
	ans += n - cnt;
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		memset(map,0,sizeof(map));
		ans = 0;
		sum = n + 1; //sum表示只去掉一條邊的條數
		for(int i = 1; i <= n + 1; i++)
		{
			scanf("%d%d",&edge[i].u,&edge[i].v);
			map[edge[i].u][edge[i].v]++;
			map[edge[i].v][edge[i].u]++;
		}
		for(int i = 1; i <= n + 1; i++) //刪除第i條邊
		{
			map[edge[i].u][edge[i].v]--;
			map[edge[i].v][edge[i].u]--;
			solve();
			map[edge[i].u][edge[i].v]++; //恢復第i條邊
			map[edge[i].v][edge[i].u]++;
		}
		printf("%d\n",ans / 2 + sum);
	}
	return 0;
}


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