Colored Sticks
Time Limit: 5000MS | Memory Limit: 128000K | |
Total Submissions: 27380 | Accepted: 7241 |
Description
You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a straight line such that the colors of the endpoints that touch are of the same color?
Input
Input is a sequence of lines, each line contains two words, separated by spaces, giving the colors of the endpoints of one stick. A word is a sequence of lowercase letters no longer than 10 characters. There is no more than 250000 sticks.
Output
If the sticks can be aligned in the desired way, output a single line saying Possible, otherwise output Impossible.
Sample Input
blue red red violet cyan blue blue magenta magenta cyan
Sample Output
Possible
Hint
Huge input,scanf is recommended.
现在你手中有很多两头涂了颜色的木棒,输入给出所有的木棒,以EOF结束,当两根木棒的各自一头具有相同颜色的时候,你就可以把这两根木棒接起来。问你是否可以把这些木棒都接起来。
解题思路:
如果我们把一种颜色看成图上面的一个顶点,在一根木棒上面的两种颜色就可以表示一条无向边,那么我们只要找到一条路径,经过所有的点一次且仅一次,那么就输出Possible,否则输出Impossible。学过离散数学等知识的童鞋可以清楚的知道,就是要我们求一个无向图的欧拉通路。当该图是连通的,并且只有2个或者没有奇度顶点的时候,这样的通路才存在。好了,剩下来的就是对于字符串索引的一个问题了。250000的输入数据,但是每个不会超过10的长度,我们当然用字典树进行处理。他每次的查找次数不会超过10次。所以就在我们建立字典树的时候,每建立完成一个颜色的单词,就把它对应的度+1。在对结果进行判断的时候,我们理所当然要优先用并查集来判断图是否连通,要是不是连通图,那么我们就没有其他操作的必要了,直接输出Impossble。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 500008
int father[maxn];
int rank[maxn];
int deg[maxn];
int up,no;
bool vis[maxn];
struct Trie
{
Trie *next[26];
bool flag;
int num;
void init ()
{
memset ( next , NULL , sizeof ( next ) );
num = -1;
flag = false; //存在标记
}
};
int createTrie ( Trie *root , char *str ) //创建字典树过程
{
int len = strlen ( str );
Trie *p = root, *q;
for ( int i = 0 ; i < len ; i ++ )
{
int id = str[i] - 'a';
if ( p->next[id] == NULL )
{
q = new Trie;
q->init();
p->next[id] = q;
p = p->next[id];
}
else
p = p->next[id];
}
if ( !p->flag ) //如果这个单词没有没创建过,那么我们给他一个编号,并且更新我们的颜色总数
{
p->flag = true;
p->num = no;
no++;
}
return p->num; //一种颜色的单词创建完毕后,我们返回它编号
}
void init_set ( int x )
{
father[x] = x;
rank[x] = 0;
}
int find_set ( int x )
{
if ( x != father[x] )
{
father[x] = find_set ( father[x] );
}
return father[x];
}
void union_set ( int x, int y ) //将x,y所代表的集合合并
{
x = find_set ( x );
y = find_set ( y );
if ( x==y ) return ;
if ( rank[x] > rank[y] ) father[y] = x;
else
{
if ( rank[x] == rank[y] )
{
rank[y] ++;
}
father[x] = y;
}
}
int main()
{
Trie *root = new Trie;
root->init();
char str[25],str1[12],str2[12];
int num = 0,v=0;
for ( int i = 0 ; i < maxn ; i ++ )
init_set( i );
memset ( deg , 0 , sizeof ( deg ) );
while ( gets ( str ) )
{
int len = strlen ( str ),i,j;
for ( i = 0 ; str[i] != ' ' ; i ++ )
str1[i] = str[i];
str1[i] = '\0';
for ( i = i + 1 , j = 0 ; i < len ; i ++ , j ++ )
str2[j] = str[i];
str2[j] = '\0';
int a = createTrie ( root , str1 );
int b = createTrie ( root , str2 );
vis[a]=vis[b]=1;
union_set (a , b ); //合并为一个集合,相当于一条无向边
deg[a] ++;
deg[b] ++;
}
if ( no == 0 )
{
printf ( "Possible\n" );
return 0;
}
for ( int i = 0 ; i < no ; i ++ )
{
if ( vis[i] && father[i] == i )
{
num ++;
}
if ( vis[i] && ( deg[i] % 2 == 1 ))
v ++;
}
if ( num != 1 ) printf ( "Impossible\n" );
else
{
if ( v == 0 || v == 2 ) printf ( "Possible\n" );
else printf ( "Impossible\n" );
}
return 0;
}
技巧总结:
综合性很强,但是题目不难,只要求掌握基础的知识即可。