[poj 2513] Colored Sticks

Colored Sticks

Time Limit: 5000MS Memory Limit: 128000K
Total Submissions: 37759 Accepted: 9894

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

题目的意思就是给你一大堆木棍,两端各是一种颜色(可能相同),然后同种颜色的端点才能接在一起。问是否能满足要求地将所有木棍接起来(结成一条直线)。

我们可以将一种颜色看做一个点。那么,最后如果能接成,一点是这样的:

c1 c1...c1 c2 c2...c2...ck ck...ck

显然,这就是k个颜色段。

再直接点——

假如有一根一段为u,一段为v的木棍,那么,它能连接起一段为u,一段不为v的木棍和一段为不u,一段为v的木棍。

也就是说,我们处理出当前木棍的两端的颜色上一次出现的位置,他们尽管不是一个位置的,但是同一个颜色的,所以可以用一个并查集合并起来。

我们最后要求的是什么呢?一条满足的直线。实际上,这条直线上,每种颜色要么出现奇数次,要么偶数次。

如果是possible,说明要么就是全出现偶数次,要么刚好出现了2种出现奇数次的颜色(作为直线的两端),这就是欧拉路径。

然后还要保证,只有一个连通块,也就是并查集后所有的fa[i]都相等。

还有一个问题,为了不T掉,我们应当采用字典树来存取颜色,查找效率更高。

code:

 1 %:pragma gcc optimize(2)
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define M(a,x) memset(a,x,sizeof a)
 6 using namespace std;
 7 const int N=2500005;
 8 int n,Q,tot,ans,his[N],fa[N],cnt[N];
 9 struct Persistent_Trie {
10     int sz,ch[500005][26];
11     void init() {sz=1,M(ch,0);}
12     int insert(char s[]) {
13         int len=strlen(s),u=1;
14         for (int i=0; i<len; i++){
15             int c=s[i]-'a';
16             if (!ch[u][c]) ch[u][c]=++sz;
17             u=ch[u][c];
18         }
19         if (!his[u]) his[u]=++tot;
20         return his[u];
21     }
22 }pt;
23 inline int read() {
24     int x=0; char ch=getchar();
25     while (ch<'0'||ch>'9') ch=getchar();
26     while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
27     return x;
28 }
29 int get(int x) {return fa[x]==x?x:fa[x]=get(fa[x]);}
30 int main() {
31     char s1[20],s2[20]; pt.init();
32     memset(his,0,sizeof his),tot=0;
33     for (int i=1; i<=500005; i++) fa[i]=i,cnt[i]=0;
34     while (scanf("%s%s",s1,s2)!=EOF) {
35         int idx1=pt.insert(s1),idx2=pt.insert(s2);
36         cnt[idx1]++,cnt[idx2]++;
37         idx1=get(idx1),idx2=get(idx2);
38         if (idx1==idx2) continue; else fa[idx1]=idx2;
39     }
40     int odd=0,c=0;
41     for (int i=1; i<=tot; i++) {
42         if (cnt[i]&1) odd++;
43         if (fa[i]==i) c++;
44     }
45     if (tot==0) puts("Possible"); else
46     if (c==1&&odd<3&&odd%2==0) puts("Possible");
47     else puts("Impossible");
48     return 0;
49 }
View Code

转载于:https://www.cnblogs.com/whc200305/p/7501828.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值