POJ1386Play on Words-歐拉回路判定

題目鏈接:http://poj.org/problem?id=1386

題目大意:給定n個單詞序列,求能否將所有的單詞首尾相連,第一個和最後一個可以不相連。

題目思路:單詞由小寫字母組成,因爲本題中我們只關注單詞的首尾字母,那麼我們就可以抽象出一個有向圖,將每個字母抽象成一個節點,每個單詞表示成一條有向邊,單詞的首字母和最後一個字母便是邊的兩個節點!那麼本題就轉換成能否從一個點出發,將所有的邊遍歷一次!邊不能重複遍歷。即判定該有向圖是否存在歐拉通路!該有向圖可能不連通,所以需要判斷是否連通。

看代碼註釋:

<span style="font-size:14px;">#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100010
#define MAXN 30
typedef struct edge   //記錄由單詞抽象出來的邊。
{
        int x,y;        
}edge; 
edge E[MAX];
int parent[MAXN];  //並查集判斷圖是否連通時的標記數組
int x[MAXN],y[MAXN],count[MAXN];  //分別表示頂點的出度,入度,和該節點在有向圖中是否用到。
char s[MAX];
int n;
void UFset()
{
     int i;
     for (i=0;i<MAXN;i++)
     {
         parent[i]=-1;    
     }     
}
int find(int x)
{
    int s;
    for (s=x;parent[s]>=0;s=parent[s]);
    while (s!=x)
    {
          int temp=parent[x];
          parent[x]=s;
          x=temp;
    }
    return s;
}
void unio(int R1,int R2)
{
     int r1=find(R1);
     int r2=find(R2);
     
     int temp=parent[r1]+parent[r2];
     if (parent[r1]>parent[r2])
     {
        parent[r2]=temp;
        parent[r1]=r2;                          
     }
     else
     {
        parent[r1]=temp;
        parent[r2]=r1;     
     }
}
int bconnet()
{
    int i,j;
    UFset();
    for (i=0;i<n;i++)  </span><span style="font-size:14px; font-family: Arial, Helvetica, sans-serif;">//將所有連通的頂點合併</span><span style="font-size:14px;">
    {
        int u=E[i].x;
        int v=E[i].y;
        if (u!=v&&find(u)!=find(v))
        {
           unio(u,v);   
           //printf("%d %d\n",u,v);
        }
    }
    int first=-1;
    for (i=0;i<26;i++)  
    {
        if (!count[i])
        {
         continue;        
        }    
        if (first==-1)
           first=i;
        if (find(first)!=find(i))
           break;
    }
    //printf("%d\n",i);
    if (i<26)
       return 0;
    return 1;   
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
          int i,j,odd=0,m,in=0,out=0,flag=1;
          scanf("%d\n",&n);
          memset(x,0,sizeof(x));
          memset(y,0,sizeof(y));
          memset(count,0,sizeof(count));
          for (i=0;i<n;i++)
          {
              scanf("%s",s);
              m=strlen(s);
              int u=s[0]-'a';
              int v=s[m-1]-'a';
              x[u]++;   //記錄出度
              y[v]++;  //記錄入度                   
              count[v]=count[u]=1;  //標記該節點存在該有向圖中
              E[i].x=u;
              E[i].y=v;
              //printf("%d %d\n",E[i].x,E[i].y);
          }
          for (i=0;i<26;i++)   //判斷有向歐拉圖的定理
          {
              if (!count[i])
              {
                 continue;              
              }
              if (x[i]==0&&y[i]==0)   //如果該頂點存在在有向圖中,但是出入度都爲零,那麼表示他是個孤立點,則不可能存在歐拉通路
              {
                 flag=0;
                 break;
              }
              if (x[i]-y[i]>1||y[i]-x[i]>1)  //</span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size:12px;">出入度差距大於1,不存在歐拉通路</span></span><span style="font-size:14px;">
              {
                 flag=0;
                 break;                             
              }
              if (x[i]-y[i]==1)  
              {
                    out++;
                    if (out>1)
                    {
                       flag=0;
                       break;          
                    }
              }
              if (y[i]-x[i]==1)
              {
                 in++;
                 if (in>1)                 
                 {
                    flag=0;
                    break;                          
                 }
              }
          }
          if (in!=out)
             flag=0;
          if (!bconnet())  //判斷是否連通
             flag=0;
          if (flag)
             printf("Ordering is possible.\n");
          else
             printf("The door cannot be opened.\n"); 
    }
    return 0;
} 
</span>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章