HDU1116Play on Words(欧拉回路+并查集)

题意:

       给你一连串的单词,每个单词只要能够首位相连就可以输出  Ordering is possible.否则输出The door cannot be opened.
解题思路:

       典型的欧拉回路,把每个单词的首字母跟尾字母作为节点,然后算每个节点的入度跟出度,

       1.首先应判断这个图是否有连通分量,如果有连通分量,那么这个图就不满足。

       2.当图没有连通分量满足时,算如果每个节点的入度于出度都是偶数,那么就是一个欧拉回路,这种情况满足。

          另一种是欧拉通路,即一个节点只有入度,另一个节点只有出度就可以满足。

发发牢骚:

       因为初始化的时候i=1;i<=MAX;i++时这个=号越界了,搞得我头都大了。。

       玄得狠,不过也证明一个问题,熟悉的错不了,认真分析一遍还是可以分析出来的,细心透彻地分析很重要。

代码:

#include<iostream> 
#include<string> 
using namespace std; 
 
const int MAX=30
int father[MAX],dep[MAX],in[MAX],out[MAX],visited[MAX]; 
 
int find_set(int x) 

    if(x!=father[x]) 
    { 
        father[x]=find_set(father[x]);//回溯压缩路径 
    } 
    /*所有的子节点的根都归到boss下*/ 
    return father[x]; 

 
void union_set(int f1,int f2) 

    f1=find_set(f1); 
    f2=find_set(f2); 
    if(f1==f2) 
        return ; 
    if(dep[f1]>dep[f2]) 
    { 
        father[f2]=f1; 
    } 
    else 
    { 
        if(dep[f1]==dep[f2]) 
        { 
            dep[f2]++; 
        } 
        father[f1]=f2; 
    } 
    return ; 

 
void init() 

    for(int i=0;i<MAX;i++) 
    { 
     
        father[i]=i;//父节点         
        dep[i]=0;//并查集的秩 
        in[i]=0
        out[i]=0
        visited[i]=0;//节点是否访问过 
    } 

 
int main(void

    int cas,num,i,a,b,flag,count,k,p[MAX]; 
    string str; 
    scanf("%d",&cas); 
    while(cas--) 
    { 
        scanf("%d",&num);//单词个数 
        init(); 
        for(i=1;i<=num;i++) 
        { 
            cin>>str; 
            a=str[0]-'a'
            b=str[str.size()-1]-'a'
            in[a]++;//入度 
            out[b]++;//出度 
            visited[a]=1
            visited[b]=1
            union_set(a,b); 
        } 
        /*判断有向图是否连通*/ 
        for(i=0,count=0;i<MAX;i++) 
        { 
            if((visited[i])&&father[i]==i) 
                count++; 
        } 
        flag=0;//通 
 
        if(count!=1
        { 
            cout<<"The door cannot be opened."<<endl; 
            continue
        } 
        for(i=0,k=0;i<MAX;i++) 
        { 
            if(in[i]!=out[i])//找出入度与出度不相同的点 
                p[k++]=i; 
        } 
        if(k==0||k==2)//白开水思路 
        { 
            if(k==0
            {         
                flag=0
            } 
            else 
            { 
                if( out[p[0]]-in[p[0]]==1 && in[p[1]]-out[p[1]]==1   ||( out[p[1]]-in[p[1]]==1 && in[p[0]]-out[p[0]]==1 ) ) 
                { 
                    flag=0
                } 
                else 
                    flag=1
            } 
        } 
        else 
        { 
            flag=1
        } 
        if(flag) 
            cout<<"The door cannot be opened."<<endl; 
        else 
            cout<<"Ordering is possible."
<<endl; 
    } 
    //system("pause"); 
    return 0

原文地址:https://www.cnblogs.com/cchun/p/2520117.html