• 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
    ", 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;
    }
    

      

  • 相关阅读:
    maven 笔记
    面试题53:在排序数组中查找数字
    面试题52:两个链表的第一个公共节点
    面试题51:数组中的逆序对
    面试题50_2:字符流中第一个只出现一次的字符
    面试题50:第一个只出现一次的字符
    面试题49:丑数
    面试题48:最长不含重复字符的连续子字符串
    面试题47:礼物的最大值
    面试题8:二叉树的下一个节点
  • 原文地址:https://www.cnblogs.com/lautsie/p/3788924.html
Copyright © 2020-2023  润新知