Time Limit: 5000MS | Memory Limit: 128000K | |
Total Submissions: 38355 | Accepted: 10044 |
Description
Input
Output
Sample Input
blue red
red violet
cyan blue
blue magenta
magenta cyan
Sample Output
Possible
Hint
Source
题意:
给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的。
解题思路:
将每一根火柴棍,看成一条边,相同的颜色为同一个点,这样我们可以把原问题转化为,是否可以画一条线,经过所有边一次且仅一次。这就是欧拉图,问是否存在欧拉通路(或者欧拉回路也可以)。
欧拉通路也叫半欧拉图,欧拉回路也叫欧拉图。
无向图G是半欧拉图 当且仅当 1.G是连通的 2.恰有两个奇度定点
无向图G是欧拉图 当且仅当 1.G是连通的 2.没有奇度定点
ps:或许与人会注意到,每次插入的是一条边,每条边上有两个点,那么是否可以这样想:如果有两条边有颜色相同的点,那么就把这两个点粘起来,形成一条新边,这样一直插入所有边,如果木棍能够连接成一条直线,那么最后应该只剩下两个端点,如果大于两个端点,就不能连成一条直线。因为每次输入的是一条边,所以输入的两个点一定是连通的,将它与另一个边相接,新生成的木棍一定也是连通的,所以这种不像是判断欧拉图那样一个点一个点的输入,是否可以不判断连通性?答案是不可以,因为木棍可能两端点同色,这样,木棍在我们的模拟中,就会退化成一个点,所以这个问题又退化成了单点输入的欧拉图问题。
所以我们首先判断奇度定点的个数。将颜色string与出现次数int联系起来
如果使用map的话会超时,虽然STL的map是基于hash的基础上,但并不高效
这里使用字典树为每个字符串一个编号。
关于字典树=》浅谈Trie树(字典树)
判断是否联通肯定就是用并查集了。使用并查集时必须压缩路径,前几次搜索某个结点k的祖先时,在不断通过父亲结点寻找祖先结点时,顺便把从k到最终祖先结点S中经过的所有结点的祖先都指向S,那么以后的搜索就能把时间降低到O(1)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 const int large = 250000*2;//最多有250000*2个结点 6 int color=0;//记录当前颜色的编号 7 int Count[large+1] = {0};//第id个结点出现的次数 8 int ancestor[large+1];//第id个结点的祖先 9 10 class HashTable{ 11 public: 12 int id; 13 HashTable *next[27];//存储子树的颜色 14 HashTable()//初始化 15 { 16 id = 0; 17 memset(next,0,sizeof(next)); 18 } 19 }root;//根节点root 20 21 int hash(char *a) 22 { 23 HashTable *temp = &root;//从根节点开始查找 24 int i=0; 25 while(a[i] != '\0') 26 { 27 if(!temp->next[a[i]-'a'])//索引不存在 28 temp->next[a[i]-'a'] = new HashTable;//创建索引 29 temp = temp->next[a[i]-'a']; 30 i++; 31 } 32 if(temp->id)//颜色单词已存在 33 return temp->id;//返回其编号 34 else{ 35 temp->id = ++color; 36 return temp->id; 37 } 38 } 39 40 int find(int i) 41 { 42 if(ancestor[i] != i) 43 ancestor[i]=find(ancestor[i]);//路径压缩 44 return ancestor[i]; 45 } 46 47 void union_anc(int i,int j) 48 { 49 int pi = find(i); 50 int pj = find(j); 51 ancestor[pj] = pi;//使i的祖先作为j的祖先 52 return; 53 } 54 55 int main() 56 { 57 for(int i=0;i<=large;i++) 58 { 59 ancestor[i] = i;//初始化每个颜色id的祖先为自己 60 } 61 char a[20],b[20]; 62 while(cin>>a>>b) 63 { 64 int i = hash(a);//得到颜色编号 65 int j = hash(b); 66 ///计数增加 67 Count[i]++; 68 Count[j]++; 69 70 ///将i和j的祖先合并 71 union_anc(i,j); 72 } 73 int s = find(1);//若图为联通图,则s为所有结点的共同祖先 74 //若图为非连通图,s为所有祖先中的其中一个祖先 75 int num = 0;//度数为奇数的节点个数 76 for(int i=1;i<=color;i++) 77 { 78 if(Count[i]%2)//度为奇数 79 num++; 80 if(num>=3) 81 { 82 cout<<"Impossible"<<endl; 83 return 0; 84 } 85 if(find(i)!=s) 86 { 87 cout<<"Impossible"<<endl; 88 return 0; 89 } 90 } 91 if(num == 1) 92 cout<<"Impossible"<<endl; 93 else 94 cout<<"Possible"<<endl; 95 96 return 0; 97 }