题目链接:https://www.luogu.org/problemnew/show/P2731
这个题是欧拉回路的模板题,那么在这里给出一个hierholzer的做法。
对于求欧拉回路的问题,有Fluery算法和Hierholzers算法,两种算法。
后面一种算法无论是编程复杂度还是时间复杂度好像都比前种算法复杂度更优,但前者的应用广泛性好像比后者更高。
对于Hierholzers算法,前提是假设图G存在欧拉回路,即有向图任意点的出度和入度相同。从任意一个起始点v开始遍历,直到再次到达点v,即寻找一个环,这会保证一定可以到达点v,因为遍历到任意一个点u,由于其出度和入度相同,故u一定存在一条出边,所以一定可以到达v。将此环定义为C,如果环C中存在某个点x,其有出边不在环中,则继续以此点x开始遍历寻找环C’,将环C、C’连接起来也是一个大环,如此往复,直到图G中所有的边均已经添加到环中。
举个例子
在手动寻找欧拉路的时候,我们从点 4 开始,一笔划到达了点 5,形成路径 4-5-2-3-6-5。此时我们把这条路径去掉,则剩下三条边,2-4-1-2 可以一笔画出。
这两条路径在点 2 有交接处(其实点 4 也是一样的)。那么我们可以在一笔画出红色轨迹到达点 2 的时候,一笔画出黄色轨迹,再回到点 2,把剩下的红色轨迹画完。
既然是模板题..那么当然选择好写的
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <stack> 5 using namespace std; 6 const int maxn = 1031; 7 int G[maxn][maxn], du[maxn]; 8 int n,m; 9 stack<int> S;//用栈记录路径 10 void dfs(int u)//dfs过程中不需要恢复,用栈记录路径 11 { 12 for(int v=1; v<=n; v++) 13 if(G[u][v]) 14 { 15 G[u][v]--; 16 G[v][u]--; 17 dfs(v); 18 } 19 S.push(u); 20 } 21 int main(){ 22 23 cin>>m; 24 int u,v; 25 for(int i=1; i<=m; i++){ 26 cin>>u>>v; 27 n = max(n,u); 28 n = max(n,v); //取出点数 29 G[u][v]++; 30 G[v][u]++; 31 du[u]++; 32 du[v]++; 33 } 34 int s = 1; 35 for(int i=1; i<=n; i++) 36 if(du[i]%2==1) 37 { 38 s=i; 39 break; 40 }//选取起点 41 dfs(s); 42 while(!S.empty()){ 43 cout<<S.top()<<endl; 44 S.pop(); 45 } 46 return 0; 47 }