Poj 2513 Colored Sticks (字符串_字典树(并查集))

题目链接:http://poj.org/problem?id=2513


题目大意:给定若干个木棒,木棒两端有颜色,颜色用长度小于10的字符串描述,两根木棒能够相连当且仅当木棒两端颜色相同,问最后能把这些木棒连成一条直线吗?


解题思路:一题很综合的题目,解题需要有三方面的知识:字典树、并查集、欧拉路。木棒两端可以理解为两点,木棒为边,利用题目的木棒就可以建图。木棒端点的颜色可能重复,所以必须让每个颜色对应一个编号,用map肯定超时,因为最多有25万根木棒,50万种颜色。现在用字典树保存这些颜色,遇到一种颜色就去字典树中找,没找到就建立一个分支。

   建好图之后,就可以先判断每个点的度为多少,欧拉路有两个性质:1、图连通 2、图中度为奇数的点为0个时是回路,是2个时是通路。我们先判断后者,这样效率会高很多。判断好符合第二个条件后,用带路径压缩的并查集判断图是否连通,如果图联通肯定可以找到一个树根


测试数据:
a b
a b

END


a b
a c

END


a a

END


a a
b b
END


代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MIN 251000
#define MAX 510000 


struct node {
    
    int  flag;
    node *next[26];
}*root;
int n,tot,odd,hash[MAX],pa[MAX];
char kind1[MIN][11],kind2[MIN][11];


node *CreateNode(){
    
    node *p;
    p = (node *) malloc (sizeof(node));
    p->flag = 0;
    for (int i = 0; i < 26; ++i)
        p->next[i] = NULL;
    return p;
}
int Insert(char *str) {
    
    int i = 0,k;
    node *p = root;
    
    
    while (str[i]){
        
        k = str[i++] - 'a';
        if (p->next[k] == NULL)
            p->next[k] = CreateNode();
        p = p->next[k];
    }
    
    
    if (p->flag == 0) p->flag = tot++;
    return p->flag;     
}

int GetPa(int n){
    
    int r = n,x = n,q;
    while (r != pa[r]) r = pa[r];
    while (x != r) 
        q = pa[x],pa[x] = r,x = q;
    return r;
}


int main()
{
    int i,j,k,fir,sec; 
    
    
    i = tot = 1;
    root = CreateNode();
    memset(hash,0,sizeof(hash));
    while (scanf("%s%s",kind1[i],kind2[i]) != EOF) {
        
        k = Insert(kind1[i]);
        hash[k]++;
        k = Insert(kind2[i]);
        hash[k]++;
        i++;
    }
    
    
    n = i,odd = 0;
    for (i = 1; i < tot; ++i)     
        if (hash[i] % 2 == 1) odd++;
    if (odd != 0 && odd != 2 ) {
        
        printf("Impossible\n");
        return 0;
    }
    
	//判连通
    for (i = 1; i < tot; ++i) pa[i] = i;
    for (i = 1; i < n; ++i){
            
        k = Insert(kind1[i]);
        fir = GetPa(k);
        k = Insert(kind2[i]);
        sec = GetPa(k);
        pa[fir] = sec;
    }
        
        
    fir = GetPa(1);
    for (i = 2; i < tot; ++i) {
          
        sec = GetPa(i);
        if (sec != fir) {
                
            printf("Impossible\n");
            return 0;
        }
    }
    printf("Possible\n");
}


本文ZeroClock原创,但可以转载,因为我们是兄弟。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值