【模板】欧拉回路/路径和哈密尔顿回路
欧拉路就是经过所有的边恰好一次的路径,欧拉回路就是转转完所有边然后还要回到初始结点。
考虑欧拉回路即是所有结点出度等于入度。考虑欧拉路就是除了两个结点,一个结点出-入==1,另一个入-出==1其他出度等于入度。
然后关于欧拉路的做法,按照离散数学就是找出一个环,然后把这个环上的所有边去除掉然后再递归到各自的环上跑欧拉路。对于实现上来说,深搜可以做到这个,就是找出了一个环的同时,递归到各自下面的分支环上。做法就是搜到某个点,跑边,然后删除掉该边,继续跑,在跑完之后再将该点加入栈序列中。最终结果就是栈序列出栈的序列。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int n, m;
vector<int> ve[maxn];
unordered_set<int> se[maxn];
int rd[maxn], cd[maxn];
int sta[maxn], top;
int ded[maxn];
void dfs(int x) {
for (int it = ded[x]; it < ve[x].size(); it = ded[x]) {
ded[x] = it + 1;
dfs(ve[x][it]);
}
sta[++top] = x;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
ve[x].push_back(y);
cd[x]++, rd[y]++;
}
for (int i = 1; i <= n; i++) {
sort(ve[i].begin(), ve[i].end());
}
int qidian = 1;
int c1 = 0, c2 = 0;
bool huilu_flag = 1;
for (int i = 1; i <= n; i++) {
if (rd[i] != cd[i])
huilu_flag = 0;
if (cd[i] - rd[i] == 1)
c1++, qidian = i;
if (rd[i] - cd[i] == 1)
c2++;
if (rd[i] - cd[i] >= 2 || cd[i] - rd[i] >= 2) {
puts("No");
return 0;
}
}
if ((!huilu_flag) && !(c1 == c2 && c1 == 1)) {
puts("No");
return 0;
}
dfs(qidian);
for (int i = top; i >= 1; i--) {
printf("%d ", sta[i]);
}
}
关于哈密顿回路
目前哈密顿回路是一个NP问题,即可以最坏多项式时间复杂度判断,但是目前是指数级别求。
我们可以通过状态压缩,解决这个问题。具体就是设定f[2^n][n]表示已经经过的点状态+目前在的点。回路就在求到经过恰好所有点一次后再分别判断一下即可。如果没有固定起点,那也就是O(2^n*n^2)解决的问题。总之,状态压缩是关键。