【题解】UVA610

时间:2021-08-08
本文章向大家介绍【题解】UVA610,主要包括【题解】UVA610使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

UVA610 Street Directions

题意

给出一张无向图,尽量使多的边成为单向边且满足改变之后的图仍然是强连通图。

前言

感觉题解区的大佬们用的方法十分麻烦,实际上并不需要边双+缩点。

思路

首先,桥不能被改成单向边,因为会使得某一个方向断开;其次,除了桥之外的边会构成若干个双连通图,那么我们按照 \(\rm dfs\) 的顺序把这里面的边改成单向边,那么这个双连通图就会变成一个强连通图。

\(\rm Code\)

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

const int MAXN = 1e3 + 5;
const int MAXM = 1e6 + 5;

int cnt, Time;
int head[MAXN], dfn[MAXN], low[MAXN];

struct edge
{
	int to, nxt, vis;
}e[MAXM << 1];

void add(int u, int v)
{
	e[++cnt] = edge{v, head[u], false};
	head[u] = cnt;
}

void tarjan(int u, int fa)
{
	dfn[u] = low[u] = ++Time;
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		if (v == fa || e[i].vis)
		{
			continue;
		}
		e[i].vis = e[i ^ 1].vis = true;
		printf("%d %d\n", u, v);
		if (!dfn[v])
		{
			tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if (dfn[u] < low[v])
			{
				printf("%d %d\n", v, u);
			}
		}
		else
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
}

void init()
{
	cnt = 1;
	Time = 0;
	memset(head, 0, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
}

int main()
{
	int n, m, t = 0;
	while (scanf("%d%d", &n, &m), n + m)
	{
		init();
		for (int i = 1; i <= m; i++)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			add(u, v);
			add(v, u);
		}
		printf("%d\n\n", ++t);
		for (int i = 1; i <= n; i++)
		{
			if (!dfn[i])
			{
				tarjan(i, 0);
			}
		}
		puts("#");
	}
	return 0;
}

原文地址:https://www.cnblogs.com/mango13/p/Solution-UVA610.html