您的位置:首页 > 其它

POJ-1470 Closest Common Ancestors【LCA】

2012-04-03 20:08 211 查看
题目链接:http://poj.org/problem?id=1470

题目大意:

给你一棵树,然后求公共祖先。

只不过我们需要记录每个节点作为公共祖先的次数。然后升序输出。

解题思路:

这道题,我不想做啥评论了。。。。。。。。。你妹啊!!!!!!!!!为了你,WA了20多次啊啊啊啊啊啊啊啊啊啊啊啊!!!!!!!!

原来Wrong的代码,数组开大一点点就过了啊。。。。。。。原来WA的代码,换成G++就过了啊!!!!!!!!!!!!!

因为什么啊!!!!!!!!!!!!!

2天都被你浪费了啊!!!!

好了,发泄完毕。

这道题需要注意的问题有:

1.数据第一个不是这棵树的根,所以我们需要寻找这棵树的根,这个很好解决,在输入的时候记录每个节点的入度,那么入度为0的点就是树根。

2.测试数据有多组。

3.输入比较变态,但是处理方法很多,貌似还有scanf正则表达式的。。Orz,我用的简单的一招,哈哈。轻松水过。

4.虽然只有900个点,但是数组不要开小,我原来开的1000不过,后来开到4000就过了。郁闷。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;

#define N 4010
#define M 4010

int visit[M], level[M], first
; //深搜步骤、层、首次出现
int dp[20]
; //RMQ-dp处理
vector<int>son
; //记录孩子
int in
; //入度
int top;
int res
; //结果

void DFS(int ceng, int now)
{
	if(first[now] == -1)
		first[now] = top;
	level[top] = ceng;
	visit[top++] = now;

	if(son[now].size() == 0) //终止条件
		return ;

	for(int i = 0; i < son[now].size(); ++i)
	{
		DFS(ceng + 1, son[now][i]);
		level[top] = ceng;
		visit[top++] = now;
	}
}

void RMQ(int n) //预处理
{
	for(int i = 1; i <= n; ++i)
		dp[0][i] = level[i];
	for(int i = 1; (1 << i) <= n; ++i)
		for(int j = 1; j <= n + 1 - (1 << i); ++j)
			dp[i][j] = min(dp[i - 1][j], dp[i - 1][j + (1 << i >> 1)]);
}

int ac(int start, int end) //返回最近公共祖先
{
	int k = (int)(log((double)(end - start + 1.0)) / log(2.0));
	int temp = min(dp[ k ][ start ], dp[ k ][ end - (1 << k) + 1 ]);
	for(int i = start; i <= end; ++i) //找下标
		if(level[i] == temp)
			return visit[i];
}

void init(int n)
{
	top = 1;
	memset(in, 0, sizeof(in));
	memset(first, -1, sizeof(first));
	memset(res, 0, sizeof(res));
	for(int i = 1; i <= n; ++i)
		son[i].clear();	
}

int main()
{
	int vnum;
	int a, num, b;
	int root;
	int query, start, end;
	while(scanf("%d", &vnum) != EOF)
	{
		init(vnum); //初始化
		for(int i = 1; i <= vnum; ++i) //读入图
		{
			scanf("%d:(%d)", &a, &num);
			while(num--)
			{
				scanf("%d", &b);
				son[a].push_back(b);
				in[b]++; //入度+1
			}
		}

		for(root = 1; in[root]; ++root); //找根

		DFS(0, root); //深搜
		RMQ(2 * vnum - 1); //O(nlogn)预处理

		scanf("%d", &query);
		while(query--)
		{
			scanf(" (%d %d) ", &start, &end);
			start = first[start], end = first[end]; //找到在level中的位置
			if(start > end) //保证前小后大
				swap(start, end);
			res[ac(start, end)]++;
		}
		for(int i = 1; i <= vnum; ++i)
			if(res[i])
				printf("%d:%d\n", i, res[i]);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: