codeforces732F Tourist Reform 边双联通分量

网址:https://codeforces.com/contest/732/problem/F

题意:

给出一个无向图,现在要把它变成有向图,且要使得能到达城市的最少的点取最大值。

题解:

我们可以推理一下就知道了,我们令边双联通成环,然后桥边都指向最大的边双联通分量,则到达城市最少的点一定在最大的边双联通分量上(以下简称边双),那我们就先使用$tarjan$算法求出所有的边双。然后把这些边双先连成环,方向随意,然后把桥边连向最大的边双。我比较菜不会用$vector$成对边存储,所以就先用链式前向星。

我第一次实现的时候真实毒瘤,我先求出桥边,然后求边双,然后把所有的边双$dfs$连成环,然后把桥边调整方向,整个代码真的巨复杂。然后后面参考了网上大佬的题解,直接找出最大的边双,然后直接在最大的边双的任意一个点开始$dfs$,然后边的方向与$dfs$相反就可以了。码力太烂了QAQ

AC代码:

#include 
using namespace std;
const int N = 4e5 + 5;
struct edge
{
	int u, v, nxt;
	int tp;
};
edge e[N << 1];
int head[N];
int dfn[N], low[N], n, m, clk;
bool bri[N << 1];
int sel[N << 1];
int dcc[N], dcc_cnt, fver[N];
int dcc_num[N];
void tarjan(int u, int in_e)
{
	dfn[u] = low[u] = ++clk;
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (!dfn[v])
		{
			tarjan(v, i);
			low[u] = min(low[u], low[v]);
			if (dfn[u] < low[v])
				bri[i] = bri[i ^ 1] = 1;
		}
		else if (i != (in_e ^ 1))
			low[u] = min(low[u], dfn[v]);
	}
}
void dfs(int u, int c)
{
	dcc[u] = c;
	++dcc_num[c];
	if (!fver[c])
		fver[c] = u;
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (bri[i])
			continue;
		if (sel[i] == -1)
			sel[i] = sel[i ^ 1] = e[i].tp;
		if (dcc[v] == dcc[u])
			continue;
		dfs(v, c);
	}
}
bool vis[N];
void dfs2(int u)
{
	vis[u] = 1;
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (vis[v])
			continue;
		if (bri[i] && sel[i] == -1)
			sel[i] = sel[i ^ 1] = e[i ^ 1].tp;
		dfs2(v);
	}
}
int tot;
void add(int u, int v, int tp)
{
	e[++tot].v = v, e[tot].u = u;
	e[tot].nxt = head[u], head[u] = tot;
	e[tot].tp = tp;
}
int main()
{
	memset(sel, -1, sizeof(sel));
	int u, v;
	scanf("%d%d", &n, &m);
	tot = 1;
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d%d", &u, &v);
		add(u, v, 0);
		add(v, u, 1);
	}
	for (int i = 1; i <= n; ++i)
		if (!dfn[i])
			tarjan(i, 0);
	for (int i = 1; i <= n; ++i)
		if (!dcc[i])
			dfs(i, ++dcc_cnt);
	int maxn = 0, maxpos = 0;
	for (int i = 1; i <= dcc_cnt; ++i)
		if (maxn < dcc_num[i])
			maxn = dcc_num[i], maxpos = i;
	dfs2(fver[maxpos]);
	printf("%d\n", maxn);
	for (int i = 2; i <= (m << 1) + 1; i += 2)
	{
		if (sel[i] == 0)
			printf("%d %d\n", e[i].u, e[i].v);
		else if (sel[i] == 1)
			printf("%d %d\n", e[i].v, e[i].u);
	}
	return 0;
}

$*Tarjan$算法牛逼!

你可能感兴趣的:(codeforces732F Tourist Reform 边双联通分量)