【题解】UVA610
题意
给出一张无向图,尽量使多的边成为单向边且满足改变之后的图仍然是强连通图。
前言
感觉题解区的大佬们用的方法十分麻烦,实际上并不需要边双+缩点。
思路
首先,桥不能被改成单向边,因为会使得某一个方向断开;其次,除了桥之外的边会构成若干个双连通图,那么我们按照 \(\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;
}