欧拉回路:图G,若存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路,如果存在一条回路经过G每条边有且仅有一次,
称这条回路为欧拉回路。具有欧拉回路的图成为欧拉图。
判断欧拉路是否存在的方法
有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度。
无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的。
判断欧拉回路是否存在的方法
有向图:图连通,所有的顶点出度=入度。
无向图:图连通,所有顶点都是偶数度。
程序实现一般是如下过程:
1.利用并查集判断图是否连通,pre[i]==i的个数,如果大于1,说明不连通。
2.根据出度入度个数,判断是否满足要求。
3.利用dfs输出路径(先搜子节点,然后当前节点保存起来,最后倒着输出)。
先看个启蒙题
hdu 1878
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 10005 #define MAXN 200005 #define maxnode 1005 #define sigma_size 4 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define mid int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> const int prime = 999983; const int INF = 0x3f3f3f3f; const int INFF = 1e9; const double pi = 3.141592653589793; const double inf = 1e18; const double eps = 1e-10; const LL mod = (1<<64); /**************¶áèëía1ò*********************/ inline int read_int(){ int ret=0; char tmp; while(!isdigit(tmp=getchar())); do{ ret=(ret<<3)+(ret<<1)+tmp-'0'; } while(isdigit(tmp=getchar())); return ret; } /*******************************************/ int in[MAX]; int pre[MAX]; int n,m; void init(){ mem(in,0); for(int i=1;i<=n;i++) pre[i]=i; } int Find(int x){ return pre[x]==x?x:pre[x]=Find(pre[x]); } void Union(int a,int b){ pre[Find(a)]=pre[Find(b)]; } int main(){ while(scanf("%d",&n)&&n){ scanf("%d",&m); init(); for(int i=0;i<m;i++){ int a,b; scanf("%d%d",&a,&b); Union(a,b); in[a]++; in[b]++; } int ans=0; int flag=0; for(int i=1;i<=n;i++){ if(pre[i]==i) ans++; if(in[i]%2) flag=1; } if(ans>1||flag) printf("0\n"); else printf("1\n"); } return 0; }
poj 2337
题意:给你n个单词,让你收尾想接,把他们连成一个串,输出字典序最小的那个串
题解:首先这题的建图不能用常规方法,应该一条有向边代表一个单词,首字母和尾字母当成节点,建图
因为字典序要求最小,所以肯定是从尽可能小的字母(节点)开始dfs
首先输入单词,然后排序,从字典序大的开始建图(这样用前向星遍历图的时候,保证先遍历的边是字典序比较小的)
然后判定能否组成欧拉路(入度,出度判断之)
这样还不够,还要判断图是否连通
如果是欧拉路,那就从出度等于入度+1的那个点开始搜,如果是回路,那就从最小的节点开始搜
dfs的时候看这个节点搜过没有,如果没有的话就搜索他,然后把这条边放入ans数组中(输出顺序应该倒过来,因为你最后搜到终点的时候,先把终点前一条边放入,然后再往前放)
可以画图考虑一下,理解之后就知道欧拉路如何输出路径了(判定是很简单的,主要就路径一开始有点不知道如何输出,没把握)
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 1005 #define MAXN 200005 #define maxnode 1005 #define sigma_size 4 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define mid int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> const int prime = 999983; const int INF = 0x3f3f3f3f; const int INFF = 1e9; const double pi = 3.141592653589793; const double inf = 1e18; const double eps = 1e-10; const LL mod = (1<<64); /**************¶áèëía1ò*********************/ inline int read_int(){ int ret=0; char tmp; while(!isdigit(tmp=getchar())); do{ ret=(ret<<3)+(ret<<1)+tmp-'0'; } while(isdigit(tmp=getchar())); return ret; } /*******************************************/ struct Edge{ int v,next; int index; bool flag; }edge[MAX*MAX]; int head[MAX]; int in[MAX]; int out[MAX]; int tot; int n,m; int ans[MAX]; int cnt; string s[1005]; void add_edge(int a,int b,int i){ edge[tot]=(Edge){b,head[a],i,false}; head[a]=tot++; } void init(){ mem(in,0); mem(out,0); mem(head,-1); mem(ans,0); cnt=0; tot=0; } bool dfs(int u){ for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!edge[i].flag){ edge[i].flag=true; dfs(v); ans[cnt++]=edge[i].index; } } } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); init(); for(int i=0;i<n;i++) cin>>s[i]; sort(s,s+n); int start=100; for(int i=n-1;i>=0;i--){ int a=s[i][0]-'a'; int b=s[i][s[i].size()-1]-'a'; add_edge(a,b,i); out[a]++; in[b]++; start=min(min(a,b),start); } int as1=0; int as2=0; for(int i=0;i<26;i++){ if(in[i]==out[i]+1){ as1++; } else if(in[i]+1==out[i]){ as2++; start=i; } else if(in[i]!=out[i]) as1=3;//如果出现上面两种情况之外的不等于,那就直接说明不成立 } if(!((as1==0&&as2==0)||(as1==1&&as2==1))) printf("***\n"); else{ dfs(start); if(cnt!=n) printf("***\n");//判断是否连通 else{ for(int i=cnt-1;i>=0;i--){ cout<<s[ans[i]]; if(i) printf("."); else printf("\n"); } } } } return 0; }