POJ 2513 Colored Sticks (排序+并查集判断欧拉路)

106 篇文章 0 订阅
34 篇文章 0 订阅

题意:

给一堆棍子,棍子由头尾两个字符串组成,棍子两两相连的条件是相接的部分字符串必须相同,问能否将这些棍子组成一条直线.


解题过程:

这题其实并不需要用字典树处理,用排序统计度数一样.

一开始我想到保证度数为奇数的点的数量小于2就行了,但这样明显不可以,点数为1时就不正确.

另外最重要的一点,当度数为奇数的点数量为0或2时,可以保证每条边都会被遍历且只有一次,但是,这样的图有可能是多个欧拉分路组成的非连通图.所以仍然不能满足题目要求.

然后我改用并查集判断是否连通,提交仍然WA,去网上看了下别人的做法,除了用字典树统计度数其它没有差别,直到我看到kuangbin大神的博客里写着要考虑没有棍子的情况.....晕.


正确思路:

题目等价与判断图是否是欧拉图

判断欧拉图条件

1.图连通

2.度数为奇数的点的个数为0或奇数.

条件一用并查集判断是否满足即可

条件二用字典树或排序都可以统计判断是否满足.

注意棍子为0的数据,答案应该是可以.



代码:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
int f[501234];
struct p
{
    char a[15];
    int v;  // 对点编号.
}b[501234];
int cmp(p a, p b )
{
    return strcmp(a.a,b.a)<0;
}
int getf(int x)
{
    if(x==f[x])return x;
    else return f[x]=getf(f[x]);
}
void merg(int x, int y)
{
    x=getf(x);
    y=getf(y);
    if(x!=y)
    {
        f[y]=x;
    }
}
int main()
{
    int i=0;
    i=0;
    while(~scanf("%s", b[i].a))
    {
        b[i].v=i/2;
        i++;
        b[i].v=i/2;
        scanf("%s", b[i++].a);
    }
    sort(b, b+i, cmp);
    int n;
    n=i;
    for(i=0; i<n/2; i++)f[i]=i;
    int sum=1;   //相同字符串个数,即点的度数.
    int tosum=0; //度数为奇数点的个数
    <pre name="code" class="cpp">    for(i=0; i<n-1; i++)
    {

        if(strcmp(b[i].a, b[i+1].a)==0)
        {
            sum++;
            merg(b[i].v, b[i+1].v);
        }
        else
        {
            if(sum%2)tosum++;
            sum=1;
        }
    }
    if(sum%2)tosum++; //最后判断下最后一个点的度数是否是奇数.
    
    for(i=0; i<n/2-1; i++)
    {
       if(getf(i)!=getf(i+1))break;
    }
    
    if((tosum==0 || tosum==2) && i==n/2-1) printf("Possible\n");
    else if(n==0)printf("Possible\n");  //棍子为0的情况
    else printf("Impossible\n");
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值