Colored Sticks
字符串的题目。字典树 + 欧拉回路 + 并查集。 用并查集判断图是不是连通。我们可以以输入的颜色做为点,这样同一根棍子上的两个端点的颜色就有父子关系,我们根据这个父子关系来建立一个并查集,最后如果任意两个点都在同一个集合中,那么我们就得知图必定是连通的。然后我们在判断是不是欧拉回路,这个只需要统计点的度数是奇数的点的个数,如果大于2那么必定不存在,否则存在。我们使用字典树来存储点,并为其编号,当插入一种颜色的时候,我们可以来判断该颜色是否出现过,并且记录每种颜色的度数。
详细参看代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std ;
#define MAXN 2500000
struct Trie{
int next[26] ;
int cnt ;//记录出现的次数也即统计某个端点的度
int ord ; //记录序号
}trie[MAXN] ;
int pre[250000 * 2 + 5 ] ;//用于记录每个点的父节点
int ncount ;
int ord ;//记录每个点出现的顺序
char number ;//用于记录度数为奇数的个数
char readl[20];
char readr[20];
/*
int find_fa(int x){
int r ;
r = x ;
while(r != pre[r])
r = pre[r] ;
return r ;
}
*/
int find_fa(int x){
if(x != pre[x])
return find_fa(pre[x]) ;
return x ;
}
/*
int insert(char * a , int nx){
int b = nx ;
char * p = a ;
while( *p ){
if(trie[b].next[*p - 'a'] == 0){
trie[b].next[*p - 'a'] = ++ncount ;
}
b = trie[b].next[*p - 'a'] ;
p ++ ;
}
if(trie[b].cnt == 0){
trie[b].ord = ++ ord ;
}
trie[b].cnt ++ ;
if(trie[b].cnt & 1)
number ++ ;
else
number -- ;
return trie[b].ord ;
}
*/
int insert(char *a , int nx){
if(*a){
if(trie[nx].next[*a - 'a'] == 0){
trie[nx].next[*a - 'a'] = ++ncount ;
}
return insert(a + 1 , trie[nx].next[*a - 'a']) ;
}
else{
if(trie[nx].cnt == 0){
trie[nx].ord = ++ord ;
}
trie[nx].cnt ++;
if(trie[nx].cnt & 1)
number ++ ;
else
number -- ;
return trie[nx].ord ;
}
}
bool judge(){
for(int i = 2 ; i <= ord ; i ++){
if(find_fa(i) != find_fa(i - 1) ){
return 0 ;
}
}
return number <= 2 ;
}
void init(){
for(int i = 0 ; i < 250000 * 2 + 5 ; i ++){
pre[i] = i ;
}
}
int main(){
ncount = 0 ;
number = 0 ;
ord = 0 ;
init() ;
while(scanf("%s%s" , readl , readr) != EOF){
int a = insert(readl , 0) ;
int b = insert(readr , 0) ;
//并
pre[ find_fa(a) ] = find_fa(b) ;
}
if(judge()){
printf("Possible\n") ;
}
else{
printf("Impossible\n") ;
}
return 0 ;
}