Colored Sticks
题目链接
Time Limit: 5000MS Memory Limit: 128000K
Total Submissions: 38621 Accepted: 10108
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.
Source
The UofA Local 2000.10.14
题目大意
给出不超过250000根木棒,木棒两端有颜色,请按照一定顺序把木棒两两连接,使得所有木棒连成一条直线。
我们只可以把颜色相同的两个端点连起来。
单词(颜色)长度不超过10。
题解
已知有两种解法
第一种:
很明显就是判断欧拉通路或欧拉回路。判断连通性,所以肯定要用到并查集。然后再统计一趟入度出度,判断是否是欧拉图。
为了方便处理,我们肯定要排序。而木棒又有两头,我们就干脆把两头拆开,并带上这根木棍的信息,再排序,这样只需把相同的一段内的木棍信息合并就好了。
第二种:
和第一种的核心差不多,把排序改成用Trip树。
代码
排序+并查集
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=250005;
int n,m,fa[maxn],h[maxn];
struct js{
char s[11];
int id;//木棒信息
}a[maxn<<1];//一分为二后大小要开两倍
int get(int x){return (fa[x]==x)?x:fa[x]=get(fa[x]);}
bool cmp(js a,js b)
{
int i=0;
while (a.s[i]||b.s[i])
{
if (a.s[i]!=b.s[i])
return a.s[i]<b.s[i];
i++;
}
return 0;
}
void read(char *s)
{
int x=0;char ch=getchar();
while (ch!=EOF&&(ch<'a'||ch>'z')) ch=getchar();
if (ch==EOF) {s[0]='@';return;}
while (ch>='a'&&ch<='z') s[x]=ch,x++,ch=getchar();
s[x]=0;
}
bool pd(js a,js b)
{
int i=0;
while (a.s[i]||b.s[i])
if (a.s[i]!=b.s[i]) return 0;
else i++;
return 1;
}
int main()
{
m=0;
while (1)
{
m++;
read(a[m].s);
if(a[m].s[0]=='@') break;
a[m].id=m+1>>1;
m++;
read(a[m].s);
a[m].id=m+1>>1;
}
m--;n=m>>1;
for (int i=1;i<=n;i++) fa[i]=i;
sort(a+1,a+m+1,cmp);
int now=1;h[1]=1;
for (int i=1;i<m;i++)
{
if (pd(a[i],a[i+1]))
{
int fx=get(a[i].id),fy=get(a[i+1].id);
if (fx!=fy) fa[fx]=fy;
h[now]++;
}else h[++now]=1;
}
int lst=get(1),s=0;
for (int i=2;i<=n;i++)
if (get(i)!=lst) {printf("Impossible");return 0;}
for (int i=1;i<=now;i++)
if (h[i]&1) s++;
if (s<3) printf("Possible");
else printf("Impossible");
return 0;
}
Trip树+并查集
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=250005;
int n,m,sum,fa[maxn];
char s[11];
struct trip_node{
int val,s;
trip_node *nxt[26];
trip_node(){val=0;s=0;for(int i=0;i<26;i++)nxt[i]=NULL;}//初始化
}*rot=new trip_node;
int get(int x){return (fa[x]==x)?x:fa[x]=get(fa[x]);}
void Insert(char *s,int len,int tot)
{
trip_node *x=rot;
for (int i=0;i<=len;i++)
{
int id=s[i]-'a';
if (x->nxt[id]==NULL) x->nxt[id]=new trip_node;//创建新节点
x=x->nxt[id];
if (i==len)
{
if (!x->val) x->val=tot;
int fx=get(x->val),fy=get(tot);
if (fx!=fy) fa[fx]=fy;
//并查集合并
if ((++(x->s))&1) sum++;else sum--;
}
}
}
void read(char *s){s[0]=0;scanf("%s",s);}
int main()
{
n=0;
for (int i=1;i<=250000;i++) fa[i]=i;
while (1)
{
read(s);
if(s[0]==0) break;
n++;
Insert(s,strlen(s)-1,n);
read(s);
Insert(s,strlen(s)-1,n);
}
if (!n) {printf("Possible");return 0;}
if (sum>2) {printf("Impossible");return 0;}
int lst=get(1);
for (int i=2;i<=n;i++)
if (get(i)!=lst) {printf("Impossible");return 0;}
printf("Possible");
return 0;
}