欧拉回路就是一笔画问题,这题的dfs算法就是无脑枚举,找到一条可行的路
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m;
int head[N];
int in[N],ot[N];
int st=1;
bool ol() {
int c=0,p=0;
for (int i=1; i<=n; i++) {
if (in[i]==0&&ot[i]==0) return false;
if(in[i]==ot[i]) c++;
if(in[i]-ot[i]==1) p++;
if(in[i]-ot[i]==-1) st=i,p++;
}
if(c==n) return true;
if(c==n-2&&p==2) return true;
return false;
}
int cnt;
struct Edge {
int to,next,num;
} edge[N];
struct E {
int v;
int u;
} e[N];
void addedge(int b,int e) {
cnt++;
edge[cnt].to=e;
edge[cnt].next=head[b];
head[b]=cnt;
}
bool cmp(E a,E b) {
if(a.u==b.u)return a.v>b.v;
else return a.u<b.u;
}
int vis[N];
stack<int> s;
void dfs(int x) {
while (head[x]) {
int w=head[x];
head[x]=edge[w].next;
dfs(edge[w].to);
}
s.push(x);
// vis[x]=1;
}
int d[N];
int main() {
cin>>n>>m;
for(int i=1; i<=m; i++) {
int u,v;
cin>>u>>v;
ot[u]++;
in[v]++;
e[i].u=u,e[i].v=v;
}
sort(e+1,e+1+m,cmp);
for(int i=1; i<=m; i++) {
addedge(e[i].u,e[i].v);
}
if(!ol()) {
cout<<"No";
return 0;
}
else dfs(st);
// for(int i=1;i<=n;i++)if(!vis[i]){ cout<<"No";return 0;}
while(s.size()) {
cout<<s.top()<<" ";
s.pop();
}
return 0;
}
这个程序中对走过的边会删除,防止重复走同一条路。但dfs算法的无脑枚举会导致时间复杂度的爆炸,也就需要用到另一种思路fleury算法。fleury算法的精髓在于不到最后不走走桥边,桥边是去掉这条边整个图就会分为两个联通块。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;
int head[N];
int in[N],ot[N];
int st=1;
bool ol() {
int c=0,p=0;
for (int i=1; i<=n; i++) {
if (in[i]==0&&ot[i]==0) return false;
if(in[i]==ot[i]) c++;
if(in[i]-ot[i]==1) p++;
if(in[i]-ot[i]==-1) st=i,p++;
}
if(c==n) return true;
if(c==n-2&&p==2) return true;
return false;
}
struct Edge {
int to,next,num;
} edge[N*2];
struct E {
int v;
int u;
} e[N*2];
void addedge(int b,int e) {
static int cnt=0;
cnt++;
edge[cnt].to=e;
edge[cnt].next=head[b];
head[b]=cnt;
}
bool cmp(E a,E b) {
if(a.u==b.u)return a.v>b.v;
else return a.u<b.u;
}
int vis[N];
stack<int> s;
void dfs(int x) {
s.push(x);
int w=head[x];
if(w)
{
head[x]=edge[w].next;
dfs(edge[w].to);
}
}
int path[N*2];int cnt=0;
void fleury(int st) {
while (!s.empty()) s.pop();
s.push(st);
while(cnt<m+1) {
int k=s.top();s.pop();
// cout<<k<<" ";
if(head[k]) {
dfs(k);
}
else path[++cnt]=k;
if(s.empty())break;
}
}
int d[N];
int main() {
cin>>n>>m;
for(int i=1; i<=m; i++) {
int u,v;
cin>>u>>v;
ot[u]++;
in[v]++;
e[i].u=u,e[i].v=v;
}
sort(e+1,e+1+m,cmp);
for(int i=1; i<=m; i++) {
addedge(e[i].u,e[i].v);
}
if(!ol()) {
cout<<"No";
return 0;
}
else fleury(st);
// cout<<st;
for(int i=cnt;i>=1;i--)
{
cout<<path[i]<<" ";
}
return 0;
}
这个程序中dfs的用处是删边,将已经走过的边删除,同时我们发现dfs时并没有刻意避开桥边,这是因为fleury函数在程序中是用来判断孤立点的,当它发现一个孤立点是就会将其加入队列,然后对剩下的点继续dfs,dfs会不断制造孤立点,最终当所有点都被走过,就完成了