poj 2513 Trie树+Euler回路+并查集

      参考:http://blog.csdn.net/lyy289065406/article/details/6647445     http://www.slyar.com/blog/poj-2513-c.html(谢谢他们)

    这题主要是会把问题给转换为求Euler回路,即一笔画成并且不重复,反正我是想不到这点。把所有的端点当成顶点,木棍当成回路。这样就可以用判断是否能构成Euler回路来判断是否能连成一条直线。而判断是否能构成欧拉回路主要是根据它的两条性质:1.图是连通的;2.奇数节点的个数为0或者2。  对于判断图是否是连通的,我们可以用并查集来判断,如果是连通的,那么所有节点的fahter节点都应该是同一个节点。  然后再把每个节点的度数记录下来,就可以判断是否存在欧拉回路了。  由于输入的是字符,而且字符的长短还不一样,不好记录颜色的编号,于是我们想到可以用Trie树来判断每个颜色的编号。就这样,这题就解决了。所涉及的知识比较多,但都不是很难的,关键还是要会运用。

#include <iostream>
#include <fstream>

using namespace std;

const int sunnum=27,base='a';
#define MAX 500005

class Trie{

    public:
        bool terminal; //标记单词的结束
        int id;     //颜色的id
        Trie *sun[sunnum];
        Trie()
        {
            terminal=false;
            id=0;
            memset(sun,0,sizeof(sun));
        }
}root;

int color=0; //总的颜色个数
int degree[MAX]={0};  //第id个节点的总度数
int father[MAX];   //第id个节点的祖先
int rank[MAX];   //表示第id个节点的秩


void make_set(int x)
{
    for(int i=1; i<=x; i++)
    {
        father[i]=i;
    }
}

//寻找祖先节点
int find_father(int x)
{
    if(x!=father[x])
        father[x]=find_father(father[x]);
    return father[x];
}


//合并x->y
void union_set(int x,int y)
{
       int px=find_father(x);
       int py=find_father(y);
        father[px]=py;
}

//寻找颜色对应的值
int hash(char *s)
{
    Trie *temp=&root;
    while(*s)
    {
        int k=*s-base;
        if(temp->sun[k]==0) temp->sun[k]=new Trie();
        temp=temp->sun[k];
        s++;
    }
    if(temp->terminal)  //单词存在
    {  
              return temp->id;
    }
    else
    {
            temp->terminal=true;
                temp->id=++color;
        return temp->id;
    }
}

int main()
{
    char a[11],b[11];
    int i,j,odd_num=0,fa; //fa为公共祖先节点
    make_set(MAX);
    freopen("acm.txt","r",stdin);
    while( scanf("%s %s",a,b)!=EOF )
    {
        //a,b的颜色编号
        i=hash(a);
        j=hash(b);
        
        degree[i]++;
        degree[j]++;
                
        union_set(i,j);
    }

        fa=find_father(1);  //若连通,fa为所有节点的祖先节点
        for(i=1; i<=color; i++)
    {
        if(degree[i]%2==1)  //奇节点
            odd_num++;
        if(find_father(i)!=fa)    //非连通
        {
            printf("Impossible\n");
                return 0;
        }
        if(odd_num>2)
        {
            printf("Impossible\n");
            return 0;
        }
    }
    if(odd_num==1)
        printf("Impossible\n");
    else   //奇节点是0或2
        printf("Possible\n");
    return 0;
}

 

转载于:https://www.cnblogs.com/Jason-Damon/archive/2012/04/16/2451515.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值