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

最近公共祖先

时间:2016-04-07 20:41:10      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:

1. 离线算法

http://hihocoder.com/problemset/problem/1067

并查集

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define N 100005
int firCh[N], firQuery[N], set[N], cnt = 0, nm = 0;
char Name[N][100];
bool visit[N];
struct node
{
    int to;
    int next;
};
node Ch[N];
struct query
{
    int to;
    int next;
    int ans;
};
query Query[N<<2];
struct nam
{
    int num; //编号
    int next[60]; //>‘z‘-‘A‘+26
};
nam name[N << 5];

int getNum(char *s)
{
    int len = strlen(s), k = 0, c;
    for (int i = 0; i < len; i++)
    {
        c = s[i] - A;
        if (0 == name[k].next[c])
            name[k].next[c] = ++cnt;
        k = name[k].next[c];
    }
    if (0 == name[k].num)
        name[k].num = ++nm;
    return name[k].num;
}

int findPa(int n)
{
    if (set[n] != n)
        set[n] = findPa(set[n]);
    return set[n];
}

void dfs(int n)
{
    visit[n] = 1;
    int t, i;
    for (i = firCh[n]; i != 0; i = Ch[i].next)
    {
        t = Ch[i].to;
        dfs(t);
        set[t] = n;
    }
    for (i = firQuery[n]; i != 0; i = Query[i].next)
    {
        t = Query[i].to;
        if (visit[t])
        {
            int q = (i % 2) ? (i) : (i - 1);
            Query[q].ans = findPa(t);
        }
    }
}

int main()
{
    int n, m, n1, n2, num, i;
    char s1[100], s2[100];
    memset(firCh, 0, sizeof(firCh));
    scanf("%d", &n);
    for (num = 0, i = 0; i < n; i++)
    {
        scanf("%s%s", s1, s2);
        n1 = getNum(s1);
        n2 = getNum(s2);
        if (0 == Name[n1][0])
            strcpy(Name[n1], s1);
        if (0 == Name[n2][0])
            strcpy(Name[n2], s2);
        Ch[++num].to = n2;
        Ch[num].next = firCh[n1];
        firCh[n1] = num;
    }
    memset(firQuery, 0, sizeof(firQuery));
    scanf("%d", &m);
    for (num = 0, i = 0; i < m; i++)
    {
        scanf("%s%s", s1, s2);
        n1 = getNum(s1);
        n2 = getNum(s2);
        Query[++num].to = n2;
        Query[num].next = firQuery[n1];
        firQuery[n1] = num;
        Query[++num].to = n1;
        Query[num].next = firQuery[n2];
        firQuery[n2] = num;
    }
    for (i = 0; i < n; i++)
        set[i] = i;
    memset(visit, 0, sizeof(visit));
    dfs(1);
    for (i = 0; i < m; i++)
        printf("%s\n", Name[Query[i*2+1].ans]); 

    return 0;
}

 

2. 在线算法

http://hihocoder.com/problemset/problem/1069

求每个结点所在层数,先序遍历树记录路径,用rmq数组记录区间内最小层数(rmq[i][j]表示从第i个结点开始长度为2^j的区间内的高度最小值)。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#define N 100005
char name[N][100];
int chNum = 0, nameCnt = 0, nameNum = 0, firCh[N], h[N], height = 0, trvs[N << 1], num = 0, rmq[N<<1][20];
bool v[N];

struct nam
{
    int num;
    int next[60];
};
nam Name[N << 5];

struct node
{
    int to;
    int next;
};
node Ch[N];

int getNum(char *s)
{
    int len = strlen(s), c, k, i;
    for (i = 0, k = 0; i < len; i++)
    {
        c = s[i] - A;
        if (0 == Name[k].next[c])
            Name[k].next[c] = ++nameCnt;
        k = Name[k].next[c];
    }
    if (0 == Name[k].num)
        Name[k].num = ++nameNum;
    return Name[k].num;
}

int dfs(int k)
{
    v[k] = 1;
    h[k] = ++height;
    trvs[++num] = k;
    for (int i = firCh[k]; i; i = Ch[i].next)
    {
        dfs(Ch[i].to);
        trvs[++num] = k;
    }
    height--;
    return 0;
}

int calRMQ(int n) //rmq数组存的是区间内层数最小的结点的nameNum
{
    int i, j;
    for (i = 1; i <= n; i++)
        rmq[i][0] = trvs[i];
    for (i = 1; (1 << i) <= n; i++)
    {
        for (j = 1; (j + (1 << i)) <= (n + 1); j++)
        {
            int t1 = rmq[j][i - 1], t2 = rmq[j + (1 << (i - 1))][i - 1];
            if (h[t1] <= h[t2])
                rmq[j][i] = t1;
            else
                rmq[j][i] = t2;
        }
    }
    return 0;
}

int find(int *p, int pos, int len)
{
    for (int i = len; i > 0; i--)
    {
        if (pos == p[i])
            return i;
    }
    return 0;
}

int getFa(int n1, int n2)
{
    if (n1 == n2)
        return n1;
    int p1, p2;
    p1 = find(trvs, n1, num);
    p2 = find(trvs, n2, num);
    if (p1 > p2)
    {
        p1 = p1^p2;
        p2 = p1^p2;
        p1 = p1^p2;
    }
    int t = (int)(log((float)(p2 - p1)) / log(2.0));
    int t1 = rmq[p1][t], t2 = rmq[p2 - (1 << t) + 1][t];
    if (h[t1] < h[t2])
        return t1;
    else
        return t2;
}

int main()
{
    int n, m, n1, n2, i;
    char s1[100], s2[100];
    scanf("%d", &n);
    for (i = 0; i < n; i++)
    {
        scanf("%s%s", s1, s2);
        n1 = getNum(s1);
        n2 = getNum(s2);
        if (!name[n1][0])
            strcpy(name[n1], s1);
        if (!name[n2][0])
            strcpy(name[n2], s2);
        Ch[++chNum].to = n2;
        Ch[chNum].next = firCh[n1];
        firCh[n1] = chNum;
    }
    memset(v, 0, sizeof(v));
    dfs(1);
//    for (i = 1; i <= num; i++)
//        printf("%d ", trvs[i]);
//    printf("\n");
    calRMQ(num);
    scanf("%d", &m);
    for (i = 0; i < m; i++)
    {
        scanf("%s%s", s1, s2);
        n1 = getNum(s1);
        n2 = getNum(s2);
        int fa = getFa(n1, n2);
        printf("%s\n", name[fa]);
        //printf("%d\n", fa);
    }

    return 0;
}

 

最近公共祖先

标签:

原文地址:http://www.cnblogs.com/argenbarbie/p/5364997.html

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