POJ1470 Closest Common Ancestors

LCA问题,用了离线的tarjan算法。输入输出参考了博客http://www.cnblogs.com/rainydays/archive/2011/06/20/2085503.html
tarjan算法是用了dfs+并查集的方式做的。这里输入输出有个不错的地方,就是用scanf("%[^0-9]", st);跳过非数字。
里面用数组g来表示多维的树,还用并查集的id数组的-1来表示是否访问。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

#define MAXN 909

/*
g for the edges
hasroot for whether the node is under root, it helps to identify the root
id for disjoint-set
lca for LCA of two nodes
sum for the count for ancestors in result
*/
int n, root;
bool g[MAXN][MAXN], hasroot[MAXN];
int id[MAXN], lca[MAXN][MAXN];
int sum[MAXN];

void input()
{
    int a, b, m;
    char str[100];
    memset(g, 0, sizeof(g));
    memset(hasroot, 0, sizeof(hasroot));
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a);
        a--;
        scanf("%[^0-9]", str);
        scanf("%d", &m);
        scanf("%[^0-9]", str);
        for (int i = 0; i < m; i++)
        {
            scanf("%d", &b);
            b--;
            hasroot[b] =true;
            g[a][b] = g[b][a] =true;
        }
    }
    for (int i = 0; i < n; i++)
        if (!hasroot[i])
        {
            root = i;
            break;
        }
}

// for disjoint-set
int find(int i)
{
	if (id[i] == i)
		return i;
	return id[i] = find(id[i]);;
}

void merge(int i, int j)
{
	id[find(i)] = find(j);
}

// do the tarjan algo and update lca table
void tarjan(int rt)
{
	id[rt] = rt;
	// id[k] != -1 means visited
	for (int i = 0; i < n; i++)
		if (g[rt][i] && id[i] == -1)
		{
			tarjan(i);
			merge(i, rt); // the order matters, because of the implementaion of merge
		}
	for (int i = 0; i < n; i++)
		if (id[i] != -1)
			lca[rt][i] = lca[i][rt] = find(i);
}

void solve()
{
	int m;
    char str[100];
    scanf("%d", &m);
    for (int i =0; i < m; i++)
    {
        int a, b;
        scanf("%[^0-9]", str);
        scanf("%d", &a);
        scanf("%[^0-9]", str);
        scanf("%d", &b);
        a--;
        b--;
        sum[lca[a][b]]++;
    }
    for (int i =0; i < n; i++)
        if (sum[i])
            printf("%d:%d\n", i + 1, sum[i]);
}

int main()
{
	//freopen("d:\\\\t.txt", "r", stdin);
	while (scanf("%d", &n) != EOF)
	{
		char str[100];
		input();
		memset(id, -1, sizeof(id));
		memset(sum, 0, sizeof(sum));
		tarjan(root);
		solve();
		scanf("%[^0-9]", str);
	}
	return 0;
}

  

posted @ 2014-06-14 23:25  阿牧遥  阅读(195)  评论(0)    收藏  举报