歐拉路 小結(POJ 2337 爲例子)

最近把拓撲排序和歐拉路看了一遍,前面已經說了拓撲排序,今天就來說說一下,歐拉路。

從POJ 2337 這道題開始說吧。

這道的題目的意思是給你一些單詞,問你可不可以首尾連接起來。

思路:判斷是不是連通圖+歐拉圖判斷+輸出歐拉路路徑(字典序最小的)

先來說下是不是連通圖,要用到並查集(自己複習了一下, 就明瞭)

簡單說下,就是把一個節點的上司給另一個節點,省去中間的領導

直接看他隸屬哪個最大的頭目。然後再看看是不是所有人的老大是不是一個人~。


歐拉路的判斷:

無向歐拉圖:所有節點的度數(出度+入度)都是偶數

或者只有兩個點的度數爲奇數,這兩個點是起點和中點

有向歐拉圖:所有點的入度=出度

或者只有一點的入度=出度+1(這是起點)和只有一點的出度=入度+1(這點是起點)


然後是路徑輸出,用到DFS,用到的是圖論中的路徑連接那塊的知識。

類似於向前星。

代碼可能比較多,但是以簡單的想法慢慢寫的,好理解。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000001;
int p[maxn];
int c1[maxn*3],c2[30],cnt1,cnt2,cnt;
int cnt_in[maxn],cnt_out[maxn],kk[maxn];
int n;
int kaitou;//第一個dfs的開頭
struct P
{
    int st,ed;
    bool del;
}edge[maxn];
int vis[maxn];
struct node
{
    char s[21];
    bool operator<(const node &C)const
    {
        return strcmp(s,C.s)<0;
    }
} str[maxn];
int cmp(char *s1,char *s2)
{
    return strcmp(s1,s2)<0;
}
int cha(int x)
{
    return x==p[x]?x:cha(p[x]);
}
void bing(int x,int y)
{
    x=cha(x);
    y=cha(y);
    if(x!=y)
        p[x]=y;
}
int chahao(int x)
{
    for(int i=0; i<cnt2; i++)
        if(c2[i]==x)
            return 1+i;
}
int panduan1()
{
    memset(cnt_in,0,sizeof(cnt_in));
    memset(cnt_out,0,sizeof(cnt_out));
    for(int i=1; i<=cnt2; i++)
        p[i]=i;
    for(int i=0; i<n; i++)
    {
        int len=strlen(str[i].s);
        int x=str[i].s[0]-'a'+1;
        int y=str[i].s[len-1]-'a'+1;
        x=chahao(x);
        y=chahao(y);
        cnt_out[x]++;
        cnt_in[y]++;
      //  AddEdge(i,y);
      edge[i].st=x;
      edge[i].ed=y;
      edge[i].del=false;
        bing(x,y);
    }
    int sum=0;
    for(int i=1; i<=cnt2; i++)
        if(i==p[i])
            sum++;
    if(sum>1)
        return 0;
    return 1;
}
int panduan2()
{
    int f1=0,f2=0,sum=0;
    int t;
    // for(int i=1;i<=cnt2;i++)
   // printf("%d %d\n",cnt_in[i],cnt_out[i]);
    for(int i=1; i<=cnt2; i++)
    {
        if(cnt_in[i]==cnt_out[i])
            sum++;
        if(cnt_in[i]==cnt_out[i]+1)
            f1++;
        if(cnt_out[i]==cnt_in[i]+1)
        {
            t=i;
            f2++;
        }
    }
  //  printf("%d %d %d\n",sum,f1,f2);
    kaitou=edge[0].st;
    if(cnt2==1)
        return 1;
    if(f1==1&&f2==1)
    {
        kaitou=t;
        return 1;
    }
    if(sum==cnt2)
        return 1;
    return 0;
}
void dfs(int u)
{

   for ( int i = 0; i < n ;i++ )
	{
		if ( ! edge[i].del && edge[i].st == u )
		{
			edge[i].del = true;
			dfs ( edge[i].ed );
			kk[cnt++] = i;
		}
	}
}
void dfs_out()
{
    memset(vis,0,sizeof(vis));

    dfs(kaitou);
    printf("%s",str[kk[cnt-1]].s);
    for(int i=cnt-2;i>=0;i--)
        printf(".%s",str[kk[i]].s);
    puts("");
}

int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {

        scanf("%d",&n);
        cnt=0;
        for(int i=0; i<n; i++)
            scanf("%s",str[i].s);
        sort(str,str+n);
        // for(int i=0;i<n;i++)
        //printf("%s ",str[i].s);
        cnt1=0,cnt2=1;
        for(int i=0; i<n; i++)
        {
            int len=strlen(str[i].s);
            int x=str[i].s[0]-'a'+1;
            int y=str[i].s[len-1]-'a'+1;
            c1[cnt1++]=x;
            c1[cnt1++]=y;
        }
        //for(int i=0;i<cnt1;i++)
        // printf("%d ",c1[i]); puts("");
        sort(c1,c1+cnt1);
        c2[0]=c1[0];
        for(int i=1; i<cnt1; i++)
        {
            if(c1[i]!=c1[i-1])
                c2[cnt2++]=c1[i];
        }
        //保存不同的字母
        //  for(int i=0;i<cnt2;i++)
        // printf("%d ",c2[i]);
        if(panduan1()==0)//判斷是不是連通圖
        {
           // puts("11111");
            puts("***");
        }
        else
        {
            if(panduan2()==0)//判斷是不是歐拉圖,即一筆畫
            {
                puts("***");
            }
            else
            {
                dfs_out();
            }
        }

    }
    return 0;
}


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