您的位置:首页 > 其它

最近公共祖先

2016-04-07 19:21 211 查看
1. 离线算法
http://hihocoder.com/problemset/problem/1067
并查集

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define N 100005
int firCh
, firQuery
, set
, cnt = 0, nm = 0;
char Name
[100];
bool visit
;
struct node
{
int to;
int next;
};
node Ch
;
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)
set
= findPa(set
);
return set
;
}

void dfs(int n)
{
visit
= 1;
int t, i;
for (i = firCh
; i != 0; i = Ch[i].next)
{
t = Ch[i].to;
dfs(t);
set[t] = n;
}
for (i = firQuery
; 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
[100];
int chNum = 0, nameCnt = 0, nameNum = 0, firCh
, h
, height = 0, trvs[N << 1], num = 0, rmq[N<<1][20];
bool v
;

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

struct node
{
int to;
int next;
};
node Ch
;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: