1. 程式人生 > >caocao's bridge:無向圖求割點或橋

caocao's bridge:無向圖求割點或橋

開始想用更簡單的方法但是沒實現,只能用了二維陣列

無向圖求橋的重點就是邊(u,v)(在dfs時的父子邊)如果是橋的話有dfn[u]<low[v]

求割點是:(非本題但就是想寫了XD)

如果點u是dfs時的根,u至少有兩個子節點(當然總結點數要大於3)那他就是割點

如果不是根,有一個子節點v滿足dfn[u]>=low[v],比較好理解。

其中dfn是訪問次序,low是所在連通分量的最小dfn

還是挺坑的...(gw,gw.jpg)

1.如果開始不連通就不用派人去

2.如果連通但是橋上沒有人還要派一個人去,其他情況下相等即可(所以一直在wa)

3.這玩意可能是雙向的,雙向邊不算橋...

程式碼如下:

#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1005;
typedef vector<int> edge;
vector<edge>G(maxn);
int soilder[maxn][maxn] = {};//覺得麻煩就用了二維陣列...
int bridgenum[maxn][maxn] = {};//如果雙向就不算橋了...還會有雙向...
int low[maxn] = {}, dfn[maxn] = {};
int tim;
int ans;
int father[maxn] = {};
int N, M;//N island M bridge
void tarjan(int u,int fa)//fa是u在dfn中的父節點
{
	father[u] = fa;
	low[u] = dfn[u] = tim++;
	for (int i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if (!dfn[v])
		{
			tarjan(v,u);//開始寫反了...
			low[u] = min(low[u], low[v]);
		}
		else if (v != fa)
		{
			low[u] = min(low[u], low[v]);//因為無向圖到父節點也是有邊的,所以不能修改父節點
		}
	}
}
bool cando()//是否能做到
{
	bool flag = 0;
	for (int i = 2; i <= N; i++)
	{
		if (father[i] == 0)//本來就不連通的不需要派人,輸出0
		{
			ans = 0;
			return true;
		}
		int v = father[i];
		if (dfn[v] < low[i]&& bridgenum[v][i]==1)//,找到橋,是說兒子不會有連結到v之前的點
		{
			ans = min(ans, soilder[v][i]);
			if (ans == 0)//如果橋上沒人還要派一個人去放啊啊啊啊啊
			{
				ans = 1;
			}
			flag = true;
		}
	}
	return flag;
}
void init()
{
	ans = 99999999;//不讓用inf
	tim = 1;

	memset(soilder, 0, sizeof(soilder));
	memset(low, 0, sizeof(low));
	memset(dfn, 0, sizeof(dfn));
	memset(bridgenum, 0, sizeof(bridgenum));
	memset(father, 0, sizeof(father));//發現G不能memset...
	G = vector<edge>(maxn);
}
int main()
{
	int u, v,w;//結點和兵數
	while (1)
	{
		cin >> N >> M;
		if (N == 0 && M == 0)
		{
			break;
		}
		init();//初始化
		while (M--)
		{
			cin >> u >> v >> w;
			G[v].push_back(u);
			G[u].push_back(v);
			soilder[u][v] = soilder[v][u] = w;
			bridgenum[u][v]++;
			bridgenum[v][u]++;
		}
		tarjan(1, 0);//首個結點的父親是0
		if (cando())
		{
			printf("%d\n", ans);
		}
		else
		{
			printf("-1\n");//炸不了
		}
	}
	return 0;
}