UVA610 街的方向 题解

题目分析

一道桥的题(比模板难一点吧)。

我们要在无向图中选择一些边,使得当它们变为有向边时,该图仍能连通。

与其思考选择哪些边去改变,不如考虑哪些边不可以改

很明显,在有向图中,如果桥变成了单向边,这幅图肯定不能连通(可结合桥的定义理解)。

那么我们只需要找出桥,也就是不能更改的边,并把他们输出两次(题目要求),则剩下的边就都可以改变,就输出一次即可。

代码实现

我们以 Tarjan 找桥的模板代码为基础,来写这道题。(为什么要用 Tarjan 找桥就不用再多说了吧。)

  • 概述:很简单,是桥就不能改,不是桥就改。
  • 细节:记得判重边,如果是重边直接处理下一个节点,如果不是重边且不是桥,就直接输出一遍即可。

AC 代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 4005;
int T;
int n, m;
int cnt, hd[maxn];
struct node{
	int to, nxt;
}e[maxn * 2];
int dfn[maxn], low[maxn];
int tmp;

void init ()
{
	cnt = tmp = 0;
	memset (dfn, 0, sizeof dfn);
	memset (low, 0, sizeof low);
	memset (e, 0, sizeof e);
	memset (hd, 0, sizeof hd);
}

void add (int u, int v)
{
	e[++cnt].to = v;
	e[cnt].nxt = hd[u];
	hd[u] = cnt;
}

void tarjan (int u, int fa)
{
	int jdg = 0;
	dfn[u] = low[u] = ++tmp;
	for (int i = hd[u]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		jdg = 0;
		if (!dfn[v])
		{
			tarjan (v, u);
			low[u] = min (low[u], low[v]);
			if (low[v] > dfn[u])
			{
				printf ("%d %d\n%d %d\n", u, v, v, u);
				jdg = 1;
			}
		}
		else if (dfn[v] < dfn[u] and v != fa) low[u] = min (low[u], dfn[v]);
		else continue;
		if (jdg == 0) printf ("%d %d\n", u, v);
	}
}

int main ()
{
	int T = 0;
	while (1)
	{
		scanf ("%d %d", &n, &m);
		if(!n and !m) break;
		init ();
		for (int i = m; i > 0; i--)
		{
			int u, v;
			scanf ("%d %d", &u, &v);
			add (u, v), add (v, u);
		}
		cout << ++T << endl << endl;
		for (int i = 1; i <= n; i++)
		{
			if (!dfn[i]) tarjan (i, -1);
		}
		cout << "#" << endl;
	}
	return 0;
}
posted @ 2022-03-25 07:25  pldzy  阅读(19)  评论(0)    收藏  举报