這個代碼的初始版本不是我寫的,借鑑於https://paste.ubuntu.com/p/HTGdYC9Dbv/
這個題網上的代碼基本上都是七八十分
代碼如下,我加了詳細的註釋
//歐拉路徑的判定 這個網址寫的很詳細 https://blog.csdn.net/u014298634/article/details/79248946
#include <iostream>
#include <set>
#include <stack>
#include <cstring>
using namespace std;
const int N = 10000;
set<int> g[N + 1]; // set存儲鄰接表地圖,之所以用set是因爲set可以自動排序,這樣就方便去找字典序最小的路徑
stack<int> path; // 用於保存路徑
bool visited[N + 1][N + 1];//bool只佔用一個字節,用int的百分百空間超限,學到了
int n, m;
//尋找字典序最小的,路徑還沒走過的下個節點
int next(int node) {
for (set<int>::iterator it = g[node].begin(); it != g[node].end(); it++) {
if (!visited[node][*it]) {
return *it;
}
}
return -1;
}
// 對於爲什麼可以非遞歸來寫歐拉通路的路徑 可以參考這個網址https://blog.csdn.net/mxYlulu/article/details/90740385
void dfs(int node)
{
stack<int> S;
S.push(node);
while (!S.empty()) {
int u = S.top();
int v = next(u);
if (v != -1) {
visited[u][v] = true;
visited[v][u] = true;
S.push(v);//有下一個點 下一個點放入s
}
else {
S.pop();
path.push(u);//沒有下一個點 當前點放入path
}
}
}
int main()
{
int src, dest;
// 輸入數據
cin >> n >> m;
for (int i = 0; i<m; ++i) {
cin >> src >> dest;
g[src].insert(dest);
g[dest].insert(src);
}
//計算每個點的出入度,看看是否具有歐拉通路
int count = 0;
for (int i = 1; i <= n; i++)
if (g[i].size() % 2 == 1)
count++;
if (!(count == 0 || (count == 2 && g[1].size() % 2 == 1)))
{
cout << "-1" << endl;
return 0;
}
// 計算路徑:從結點1開始深度優先搜索
memset(visited, false, sizeof(visited));
dfs(1);
/**
這裏講解一下,由於走過的路徑不重複,所以path.size()-1就等於走過的邊的數量
如果走過的邊數等於m,就說明這是個連通圖,網上檢驗是否連通的代碼太麻煩了,還得用並查集
舉個例子 五個點,四條邊 :1 2相連 2 3相連 1 3相連 4 5相連 從1開始出發
dfs之後,path裏面存儲的是 1 2 3 1,很明顯 少遍歷了一條邊,所以這就是非連通的,輸出-1
當然 這裏的連通指的是有邊無法遍歷到,並不是有點連通不到,如果只有一個點在整個圖的外面,那是無所謂的
**/
if (path.size() == m + 1) {
// 遍歷了所有的邊,輸出結果
int t;
while (!path.empty()) {
t = path.top();
path.pop();
cout << t << ' ';
}
cout << endl;
}
else
// 輸出結果:未找到路徑
cout << -1 << endl;
return 0;
}