最近把拓扑排序和欧拉路看了一遍,前面已经说了拓扑排序,今天就来说说一下,欧拉路。
从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; }