码迷,mamicode.com
首页 > 其他好文 > 详细

zoj 3820 Building Fire Stations(树上乱搞)

时间:2014-10-13 16:29:39      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:   图论   

做同步赛的时候想偏了,状态总是时好时坏,这状态去区域赛果断得GG了。

题目大意:给一棵树,让求出树上两个点,使得别的点到两个点较近的点的距离最大值最小。

赛后用O(n)的算法搞了搞,其实这道题不算难。逗逼的没A。。

其实这两个点一定是树直径上的两个点,如果能想到这个就很好搞了,只需要求出树的直径,然后从中间位置把树拆成两颗子树,然后分别求出子树的中心就好了。

证明如下,假如我们已经求出树上的两个点u, v满足条件。那么,我们从u, v中间把树拆开肯定是最优的,这个很容易想到。然后,对于u点,肯定在原树的直径上,因为假如u点没有在直径上的话,u点一定是在子树的一个分支上,而且到树直径端点的距离小于等于u到分支端点的距离,这样的话分支定可以取代原来直径上的一个端点而成为直径,u在直径上,与假设矛盾。所以u一定在直径上,同理v也一定在直径上。然后就搞出来了==

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 202000;

vector<int> G[maxn];
vector<int> d;

bool vis[maxn];
int fa[maxn];

int bfs1(int s)
{
	int ret = -1;
	CLR(vis, false);
	vis[s] = true;
	queue<int> q; fa[s] = -1;
	q.push(s); vis[s] = true;
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		ret = u;
		for(int i = 0; i < G[u].size(); i ++)
		{
			int v = G[u][i];
			if(vis[v]) continue;
			vis[v] = true;
			q.push(v); fa[v] = u;
		}
	}
	return ret;
}

int deg[maxn];
int cnt[maxn], n;

pair<int, int> bfs2(int u, int fa)
{
	queue<int> q;
	CLR(vis, false);
	q.push(u);
	vis[u] = true;
	if(deg[u] == 0) return make_pair(u, 0);
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		for(int i = 0; i < G[u].size(); i ++)
		{
			int v = G[u][i];
			if(vis[v] || v == fa) continue;
			q.push(v); vis[v] = true;
		}
	}
	queue<pair<int, int> > q2;
	for(int i = 1; i <= n; i ++)
		if(vis[i])
		{
			if(deg[i] == 1) q2.push(make_pair(i, 0));
			else vis[i] = false;
		}
	pair<int, int> ret;
	CLR(cnt, 0);
	while(!q2.empty())
	{
		pair<int, int> u = q2.front(); q2.pop();
		ret = u;
		cnt[u.second] ++;
		for(int i = 0; i < G[u.first].size(); i ++)
		{
			int v = G[u.first][i], len = u.second + 1;
			if(v == fa || deg[v] == 1) continue;
			deg[v] --;
			if(deg[v] == 1) q2.push(make_pair(v, len));
		}
	}
	if(cnt[ret.second] > 1)  ret.second ++;
	return ret;
}

inline int get_int(){
	int ret=0;char c;
	while(!isdigit(c=getchar()));
	do {ret = (ret<<3)+(ret<<1)+c-'0';
	}while(isdigit(c=getchar()));
	return ret;
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T --)
	{
		scanf("%d", &n);
		for(int i = 1; i <= n; i ++)
			G[i].clear(), deg[i] = 0;
		for(int i = 1; i < n; i ++)
		{
			int u = get_int(), v = get_int();
			G[u].push_back(v);
			G[v].push_back(u);
			deg[u] ++; deg[v] ++;
		}
		d.clear();
		int s =	bfs1(bfs1(1));
		for(int i = s; ~i; i = fa[i])
		{
			d.push_back(i);
		}
		int u = d[d.size() / 2], v = d[d.size() / 2 - 1];
		deg[u] --; deg[v] --;
		pair<int, int> r1 = bfs2(u, v), r2 = bfs2(v, u);
		int ans = max(r1.second, r2.second);
		printf("%d %d %d\n", ans, r1.first, r2.first);
	}
}
/*
222
4
1 2
1 3
1 4
5
1 2
2 3
3 4
4 5
11
1 2
2 3
3 4
4 5
5 6
6 7
7 8
6 9
9 10
10 11

*/


zoj 3820 Building Fire Stations(树上乱搞)

标签:   图论   

原文地址:http://blog.csdn.net/ok_again/article/details/40043197

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!