POJ 2513 Colored Sticks(欧拉回路判断+字典树Trie+并查集)

POJ 2513 Colored Sticks(欧拉回路判断+字典树Trie+并查集)

http://poj.org/problem?id=2513

题意:

        给你多个木棍,每个木棍两段涂上颜色,两根木棍只有在相同颜色的一端才能连接,问你能不能使所有木棍都连接成一条直线路.

分析:

        将输入的每个颜色看出是图的一个点,然后每条木棍正好是连接了两种颜色的一条边,我们只需要判断这个图中是否存在欧拉道路或欧拉回路即可.(考虑一下这种情况,如果一根棍子首尾是同种颜色怎么办?其实这个可以不用考虑,这就是一个自环,如果不含自环的图有欧拉回路,那么含自环的图一定也有欧拉回路)

        处理流程:依次读入每根木棍的两段的颜色A和B,然后尝试将A与B插入字典树,如果不存在A颜色,就新加入A颜色,并且给A颜色一个数字编号i,B颜色的编号是j.

        i和j就是图中的两个节点且它们是连通的且它们的度数还要都+1.合并i与j的并查集(如果i与j是同种颜色,那么就不会合并它们).当处理完所有的木棍后,看看该图是不是连通的.在看看该图的所有节点的度数是不是满足下面要求:

所有点的度数都是偶数 或 只有2个点的度数是奇数.

AC代码:1A,438ms

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxnode=5000000+1000;
const int sigma_size=26;
int cnt;//记录当前已经读入了cnt个不同的颜色了
struct Trie
{
    int ch[maxnode][sigma_size];
    int val[maxnode];//单词节点的val才非0,且val[i]表示的是该单词节点的编号
    int sz;
    void init()
    {
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));
        val[0]=0;
    }
    int insert(char *s)
    {
        int n=strlen(s),u=0;
        for(int i=0;i<n;i++)
        {
            int id=s[i]-'a';
            if(ch[u][id]==0)
            {
                ch[u][id]=sz;
                val[sz]=0;
                memset(ch[sz],0,sizeof(ch[sz]));
                sz++;
            }
            u=ch[u][id];
        }
        if(val[u]==0)//新颜色
            val[u]=++cnt;
        return val[u];
    }
}trie;
const int MAXN=500000+1000;
int F[MAXN];//初始为-1
int r[MAXN];//记录每个点的度数,初始为0
int findset(int x)
{
    if(F[x]==-1)
        return x;
    return F[x]=findset(F[x]);
}
void bind(int i,int j)
{
    int fa=findset(i);
    int fb=findset(j);
    if(fa!=fb)
        F[j]=i;
}
char str1[15],str2[15];
int main()
{
    trie.init();
    memset(r,0,sizeof(r));
    cnt=0;
    memset(F,-1,sizeof(F));
    while(scanf("%s%s",str1,str2)==2)
    {
        int i=trie.insert(str1);//尝试插入新颜色
        int j=trie.insert(str2);
        r[i]++;//度数加1
        r[j]++;
        int fa=findset(i),fb=findset(j);
        if(fa!=fb)
            bind(i,j);
    }
    bool connect=true,degree=false;//图是否连通,图的节点度数是否符合要求
    for(int i=2;i<=cnt;i++)
    if(findset(i)!=findset(1))
    {
        connect=false;
        break;
    }
    if(connect)
    {
        int odd=0;
        for(int i=1;i<=cnt;i++)
            if(r[i]%2==1)
                odd++;
        if(odd==2||odd==0)
            degree=true;
    }
    if(connect && degree) printf("Possible\n");
    else printf("Impossible\n");
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值