算法提高 士兵排隊問題(拓撲排序)

試題 算法提高 士兵排隊問題

資源限制
時間限制:1.0s 內存限制:256.0MB
試題
  有N個士兵(1≤N≤26),編號依次爲A,B,C,…,隊列訓練時,指揮官要把一些士兵從高到矮一次排成一行,但現在指揮官不能直接獲得每個人的身高信息,只能獲得“P1比P2高”這樣的比較結果(P1、P2∈A,B,C,…,Z,記爲 P1>P2),如”A>B”表示A比B高。
  請編一程序,根據所得到的比較結果求出一種符合條件的排隊方案。
  (注:比較結果中沒有涉及的士兵不參加排隊)
輸入要求
  比較結果從文本文件中讀入(文件由鍵盤輸入),每個比較結果在文本文件中佔一行。
輸出要求
  若輸入數據無解,打印“No Answer!”信息,否則從高到矮一次輸出每一個士兵的編號,中間無分割符,並把結果寫入文本文件中,文件由鍵盤輸入:
樣例輸入
A>B
B>D
F>D
樣例輸出
AFBD


題解
本題是拓撲排序的裸題。
1.如何轉換爲有向圖?

  將 > 號看成 -> ,表示一個結點指向另一個結點,如 A>B ,代表A指向B,同理 A<B 代表B指向A。
2.如何將A-Z 字母轉換爲結點?
  可以把 A 看成第0個結點,那麼B的編號就是 1 … … 所以Z的編號爲25 。
3.如何實現拓撲排序?
  方法上可以使用bfs 和dfs ,這裏我用的是dfs 。dfs深搜每個結點返回的過程實際上就是拓撲排序的逆序(好好思考一下)。
  怎麼判斷該圖是否爲DAG(有向無環圖),對這道題來講,也就是什麼時候輸出 no answer 。若採用 bfs ,則判斷最後隊列中是否還有元素,如果隊列中有元素,那麼這些結點間存在環,不存在拓撲排序;採用dfs ,若在遞歸深搜中如果發現某個節點之前已經訪問過,而且還未遞歸返回,那麼就存在環
4.vis[ i ] 的三種狀態
.vis[i]=1 代表結點i訪問過了,並且已經遞歸回來了
.vis[i]=0 代表結點i未訪問過
.vis[i]=-1 代表結點i訪問過,但是還未遞歸回來

#include<bits/stdc++.h>
using namespace std;

struct edge {	
	int from;	//出邊
	int to;		//入邊
	edge(int _from, int _to) {
		from = _from;
		to =_to;
	}
};
vector<edge> G[26];		//一共26個結點
int vis[26];
stack<char> S;		//將得到的逆序拓撲排序正序

int dfs(int vertex) {		//vertex爲頂點編號
	for (int i = 0; i < G[vertex].size(); i++) {
		int v2 = G[vertex][i].to;
		if (vis[v2]==0) {	//還未訪問過
			vis[v2] = -1;
			if (dfs(v2))
				return 1;
		}
		else if (vis[v2] == -1) {	//存在環,不存在拓撲排序
			return 1;		//立刻返回,終止遞歸
		}
	}
	vis[vertex] = 1;	//它的所有後代都已經遞歸返回了,那麼更新它爲 1
	S.push('A' + vertex);		//利用棧,由逆序得到答案
	return 0;
}

int main() {
	fill(vis, vis + 26, 1);		//26個結點初始爲1,代表都已經訪問過了,
	char a[5];			//下面輸入的時候,出現的結點才更新爲0
	int x, y;

	while (fgets(a,5,stdin)&&a[0]!=EOF) {
		x = a[0] - 'A'; y = a[2] - 'A';		//存儲邊
		vis[x] = vis[y] = 0;	//0代表這些邊需要考慮
		if (a[1] == '>')
			G[x].push_back(edge(x, y));
		else
			G[y].push_back(edge(y, x));
	}

	for (int i = 0; i < 26; i++) {
		if (vis[i]==0) {
			vis[i] = -1;	//代表正在遞歸訪問,未返回
			if (dfs(i)) {
				printf("No Answer!");
				exit(0);
			}		
		}
	}

	while (!S.empty()) {
		printf("%c", S.top());
		S.pop();
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章