codeforces732F Tourist Reform(边双连通分量)

题意:

给出一个无向图,要求转变为有向图,使所有点能到达的点数的最小值最大。

要点:

就是一个边双连通分量,不过我没学过,看了一下白书,觉得就是无向图中的强连通分量,但是其中有很多细节有点难推敲,基本思路就是:边双连通分类对应无向图,找出其中内部点数最多的边双连通分量,它的内部所有点都可以到其余点(包括自己),其余的边双连通分量可以指向最大的这个,也就是说其他所有点的能到达点数是所有的点。最后从内部点数最多的边双连通分量中任意一点开始DFS即可。但是这里有个问题,将v->u作为新边是可以的,反之u->v就是错误的,找不到原因,还是多做几道对应题目比较好。

#include<iostream>
#include<cstring>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 400005;
int low[maxn], pre[maxn];
int n, m, num_max, pos_max, pos;
typedef pair<int, int> ii;
vector<ii> g[maxn];
ii ans[maxn];
stack<int> st;

void tarjan(int u, int fa)
{
	low[u] = pre[u] = ++pos;
	st.push(u);
	for (int i = 0; i < g[u].size(); i++)
	{
		int v = g[u][i].first;
		if (v == fa)
			continue;
		if (!pre[v])
			tarjan(v, u);
		low[u] = min(low[u], low[v]);
	}
	if (low[u] == pre[u])//找到桥,此时栈中存储的点就是边双连通分量中的点
	{
		int v = 0, count = 0;
		while (v != u)
		{
			v = st.top(); st.pop();
			count++;
		}
		if (count > num_max)
		{
			num_max = count;
			pos_max = u;
		}
	}
}
void dfs(int u)
{
	pre[u] = 0;
	for (int i = 0; i < g[u].size(); i++)
	{
		int v = g[u][i].first;
		int id = g[u][i].second;
		if (pre[v])
		{
			ans[id] = ii(v, u);//问题就在这里,这里如果是u->v是错误的,找不到哪里有问题
			dfs(v);
		}
		else
			ans[id] = ii(u, v);
	}
}

int main()
{
	int u, v;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
	{
		scanf("%d%d", &u, &v);
		g[u].push_back(ii(v, i));
		g[v].push_back(ii(u, i));
	}
	tarjan(1, 0);
	dfs(pos_max);
	printf("%d\n", num_max);
	for (int i = 1; i <= m; i++)
		printf("%d %d\n", ans[i].first, ans[i].second);
	return 0;
}


posted @ 2016-10-27 19:26  seasonal  阅读(94)  评论(0编辑  收藏  举报