最近把拓撲排序和歐拉路看了一遍,前面已經說了拓撲排序,今天就來說說一下,歐拉路。
從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;
}