题目链接:http://poj.org/problem?id=2513
a b
a b
a c
b b
END
题目大意:给定若干个木棒,木棒两端有颜色,颜色用长度小于10的字符串描述,两根木棒能够相连当且仅当木棒两端颜色相同,问最后能把这些木棒连成一条直线吗?
解题思路:一题很综合的题目,解题需要有三方面的知识:字典树、并查集、欧拉路。木棒两端可以理解为两点,木棒为边,利用题目的木棒就可以建图。木棒端点的颜色可能重复,所以必须让每个颜色对应一个编号,用map肯定超时,因为最多有25万根木棒,50万种颜色。现在用字典树保存这些颜色,遇到一种颜色就去字典树中找,没找到就建立一个分支。
建好图之后,就可以先判断每个点的度为多少,欧拉路有两个性质:1、图连通 2、图中度为奇数的点为0个时是回路,是2个时是通路。我们先判断后者,这样效率会高很多。判断好符合第二个条件后,用带路径压缩的并查集判断图是否连通,如果图联通肯定可以找到一个树根。
a b
a b
END
a c
END
END
b b
END
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MIN 251000
#define MAX 510000
struct node {
int flag;
node *next[26];
}*root;
int n,tot,odd,hash[MAX],pa[MAX];
char kind1[MIN][11],kind2[MIN][11];
node *CreateNode(){
node *p;
p = (node *) malloc (sizeof(node));
p->flag = 0;
for (int i = 0; i < 26; ++i)
p->next[i] = NULL;
return p;
}
int Insert(char *str) {
int i = 0,k;
node *p = root;
while (str[i]){
k = str[i++] - 'a';
if (p->next[k] == NULL)
p->next[k] = CreateNode();
p = p->next[k];
}
if (p->flag == 0) p->flag = tot++;
return p->flag;
}
int GetPa(int n){
int r = n,x = n,q;
while (r != pa[r]) r = pa[r];
while (x != r)
q = pa[x],pa[x] = r,x = q;
return r;
}
int main()
{
int i,j,k,fir,sec;
i = tot = 1;
root = CreateNode();
memset(hash,0,sizeof(hash));
while (scanf("%s%s",kind1[i],kind2[i]) != EOF) {
k = Insert(kind1[i]);
hash[k]++;
k = Insert(kind2[i]);
hash[k]++;
i++;
}
n = i,odd = 0;
for (i = 1; i < tot; ++i)
if (hash[i] % 2 == 1) odd++;
if (odd != 0 && odd != 2 ) {
printf("Impossible\n");
return 0;
}
//判连通
for (i = 1; i < tot; ++i) pa[i] = i;
for (i = 1; i < n; ++i){
k = Insert(kind1[i]);
fir = GetPa(k);
k = Insert(kind2[i]);
sec = GetPa(k);
pa[fir] = sec;
}
fir = GetPa(1);
for (i = 2; i < tot; ++i) {
sec = GetPa(i);
if (sec != fir) {
printf("Impossible\n");
return 0;
}
}
printf("Possible\n");
}
本文ZeroClock原创,但可以转载,因为我们是兄弟。