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;
}

猜你喜欢

转载自blog.csdn.net/qq_41565901/article/details/84102158