PKU 2513 Colored Sticks(并查集+Trie树+欧拉路径(回路))

题目大意:

给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相连接的一端必须是同颜色的。

解题思路:

可以用图论中欧拉路的知识来解这道题,首先可以把木棒两端看成节点,把木棒看成边,这样相同的颜色就是同一个节点

问题便转化为:给定一个图,是否存在一笔画”经过涂中每一点,每条边一次。

这样就是求图中是否存在欧拉路Euler-Path

关于度数的判断方法:

节点的度用颜色出现次数来统计,如样例中,蓝色blue出现三次(不管是出度还是入度),那么blue结点的度就为3,同样地,我们也可以通过输入得到其他全部结点的度,于是,我们有:

Magenta=2

Blue=3

Red=2

Violet=1

Cyan=2

用一个一维数组就能记录了,然后分别模2,就能判断颜色结点的奇偶性

只要奇度数的结点数的个数=1或>=3,即使图连通,也一定不存在欧拉路径

Trie树+并查集+欧拉路径

#include<cstdio>
#include<cstdlib>
#define maxn 500010
typedef struct Trie{
    int pos;
    struct Trie *next[26];
}Trie,*trie;
trie root;
int k=0,fa[maxn],d[maxn];
void Init(trie &p)
{
    p=(trie)malloc(sizeof(Trie));
    for(int i=0;i<26;i++) p->next[i]=NULL;
    p->pos=0;
}//建Trie树,返回单词编号 
int Build(trie &p,char *s,int depth)
{
    if(!s[depth]){
        if(p->pos) return p->pos;
        p->pos=++k;
        fa[k]=k,d[k]=0;//初始化祖先为自身,度数为0 
        return k;
    }//q不能定义为全局变量 
    trie q=p->next[s[depth]-'a'];
    if(q==NULL){
        Init(q);
        p->next[s[depth]-'a']=q;
    }
    return Build(q,s,depth+1);
}
int Findset(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=Findset(fa[x]);
}
void Union(int u,int v)
{
    int x=Findset(u);
    int y=Findset(v);
    if(x!=y) fa[x]=y;
}
int main()
{
    Init(root);
    char s[12],t[12];
    while(scanf("%s%s",s,t)!=EOF){
        int x=Build(root,s,0);
        int y=Build(root,t,0);
        Union(x,y);
        d[x]++,d[y]++;
    }
    int scc=0,odd=0;
    for(int i=1;i<=k;i++){
        if(fa[i]==i) scc++;//不连通 
        if(d[i]&1) odd++;//奇度节点
    }
    if(scc>1||odd>2) puts("Impossible");
    else puts("Possible");
    return 0;
}

离散化+并查集+欧拉路径

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 500010
using namespace std;
int num[maxn],fa[maxn];
int idxc=1,idxw=1,cnt;

struct Wood{
    char left[12],right[12];
}wood[maxn/2];
struct Node{
    char col[12];  
    bool operator<(const Node tmp)const{
        if(strcmp(col,tmp.col)<=0)
            return true;
        return false;
    }
}node[maxn];
//二分查找颜色对应离散的编号 
int Binary_Search(char *col){
    int l=0,r=cnt+1;
    while(r-l>1){
        int mid=(r+l)/2;
        if(strcmp(node[mid].col,col)<=0) l=mid;
        else r=mid;
    }
    return l;
}
int Findset(int x)
{
    if(fa[x]!=x) 
        fa[x]=Findset(fa[x]);
    return fa[x];
}

int main()
{
    char s1[12],s2[12];
    while(scanf("%s%s",wood[idxw].left,wood[idxw].right)!=EOF){
        strcpy(node[idxc++].col,wood[idxw].left);
        strcpy(node[idxc++].col,wood[idxw].right);
        idxw++;
    }
    sort(node+1,node+idxc);
    memset(num,0,sizeof(num));
    num[1]++,cnt=1;
    for(int i=2;i<idxc;i++){//进行离散处理,同时统计每种颜色出现的个数
        if(strcmp(node[i].col,node[i-1].col)!=0){
            strcpy(node[++cnt].col,node[i].col);
            num[cnt]++;//颜色不同保留下来
        }
        else num[cnt]++;//颜色相同直接计数
    }
    for(int i=1;i<maxn;i++) fa[i]=i;
    for(int i=1;i<idxw;i++){
        int u=Binary_Search(wood[i].left);
        int v=Binary_Search(wood[i].right);
        int x=Findset(u),y=Findset(v);  
        if(x!=y) fa[x]=y;
    }
    int scc=0,odd=0;//cnt是节点编号,也是节点个数 
    for(int i=1;i<=cnt;i++){
        if(fa[i]==i) scc++;
        if(num[i]%2) odd++;
    }
    if(idxw==1||(scc==1&&(odd==0||odd==2))) printf("Possible\n");
    else printf("Impossible\n");
}
posted @ 2017-02-16 22:10  despair_ghost  阅读(264)  评论(0编辑  收藏  举报