CCF 送貨(滿分代碼)2015-12-4

這個代碼的初始版本不是我寫的,借鑑於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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章