题目大意:给定若干个木棒,木棒两端有颜色,颜色用长度小于10的字符串描述,两根木棒能够相连当且仅当木棒两端颜色相同,问最后能把这些木棒连成一条直线吗?
解题思路:一题很综合的题目,解题需要有三方面的知识:字典树、并查集、欧拉路。木棒两端可以理解为两点,木棒为边,利用题目的木棒就可以建图。木棒端点的颜色可能重复,所以必须让每个颜色对应一个编号,用map肯定超时,因为最多有25万根木棒,50万种颜色。现在用字典树保存这些颜色,遇到一种颜色就去字典树中找,没找到就建立一个分支。
建好图之后,就可以先判断每个点的度为多少,欧拉路有两个性质:1、图连通 2、图中度为奇数的点为0个时是回路,是2个时是通路。我们先判断后者,这样效率会高很多。判断好符合第二个条件后,用带路径压缩的并查集判断图是否连通,如果图联通肯定可以找到一个树根。
END
END
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原创,但可以转载,因为我们是兄弟。