1. 程式人生 > >九度OJ-1450:產生冠軍

九度OJ-1450:產生冠軍

  這道題厲害了。= =想不明白

演算法分析:

  由於這裡的優先關係具有傳遞性,故可利用有向圖表示優先關係:“A優勝於C”==可抽象為==》“A到C之間存在有向路徑”。有了這層抽象就能進行以下分析:

①“不能出現迴圈優先關係”《==》不能出現環路:進行拓撲排序來檢測有無環路

②“存在冠軍”《==》“存在一個人優勝於所有人”《==》存在頂點v到所有其他頂點都有有向通路《==在無環條件下==》有且僅有一個頂點的入度為0(該入度0頂點就是滿足條件的頂點v)(別問我怎麼證明我也不知道= =瞎蒙的!但是肯定是對的)

故在演算法實現時只要對以上兩點進行實現即可。

題目描述:

有一群人,打乒乓球比賽,兩兩捉對撕殺,每兩個人之間最多打一場比賽。
球賽的規則如下:
如果A打敗了B,B又打敗了C,而A與C之間沒有進行過比賽,那麼就認定,A一定能打敗C。
如果A打敗了B,B又打敗了C,而且,C又打敗了A,那麼A、B、C三者都不可能成為冠軍。
根據這個規則,無需迴圈較量,或許就能確定冠軍。你的任務就是面對一群比賽選手,在經過了若干場撕殺之後,確定是否已經實際上產生了冠軍。

輸入:

輸入含有一些選手群,每群選手都以一個整數n(n<1000)開頭,後跟n對選手的比賽結果,比賽結果以一對選手名字(中間隔一空格)表示,前者戰勝後者。如果n為0,則表示輸入結束。

輸出:

對於每個選手群,若你判斷出產生了冠軍,則在一行中輸出“Yes”,否則在一行中輸出“No”。

樣例輸入:
3
Alice Bob
Smith John
Alice Smith
5
a c
c d
d e
b e
a d
0
樣例輸出:
Yes
No
//適用條件:題目給的這張圖只能有一個(弱)連通分量(但不要求強連通) 
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#define MAXSIZE 2000
using namespace std;

struct Edge{
	int thisNode;
	int nextNode;
	Edge(){
	}
	Edge(int thisNode,int nextNode){
		this->thisNode=thisNode;
		this->nextNode=nextNode;
	}
};
struct Vex{
};
struct Graph{
	int graphSize;
	vector<Edge> edge[MAXSIZE];
//	vector<Vex> vex;
	void initGraph(int graphSize){
		this->graphSize=graphSize;
		for (int i=0;i<graphSize;i++)
			edge[i].clear();
//		vex.clear();
	}
	void addEdge(int thisNode,int nextNode){
		edge[thisNode].push_back(Edge(thisNode,nextNode));
	}
};

struct NameForm{
	char list[MAXSIZE][30];
	int nameNum;
	void initForm(){
		nameNum=0;
	}
	int char2index(char *s){
		for (int i=0;i<nameNum;i++){
			if (strcmp(list[i],s)==0){
				return i;
			}
		}
		strcpy(list[nameNum],s);
		nameNum++;
		return nameNum-1;
	}
};

int main(){
	int m;
	Graph graph;
	int inDegree[MAXSIZE];
	int cnt;
	queue<int> q;
	int thisNode,nextNode;
	char s[30];
	bool firstCase;
	NameForm nameForm;
	while (cin>>m,m){
		//initiate
		for (int i=0;i<graph.graphSize;i++)
			inDegree[i]=0;
		nameForm.initForm();//initiate nameForm
		graph.initGraph(MAXSIZE);//must init graph before inputing edges,but we can't get the graphSize before input edges also
		//so use MAXSIZE instead ,temporarily
		while (!q.empty())
			q.pop();
		cnt=0;
		//input edges & cal inDegree
		for (int i=0;i<m;i++){
			cin>>s;
			thisNode=nameForm.char2index(s);
			cin>>s;
			nextNode=nameForm.char2index(s);
			graph.addEdge(thisNode,nextNode);
			inDegree[nextNode]++;
		}
		//initiate graphSize&q
		graph.graphSize=nameForm.nameNum;
		for (int i=0;i<graph.graphSize;i++){
			if (inDegree[i]==0)
				q.push(i);
		}
		//判斷初始入度為0的頂點數是否大於1,若是則肯定不可能出現冠軍 
		if (q.size()>1){
			cout<<"No"<<endl;
			continue;
		}
		//Topological sorting 
		/*
		使用佇列q作為線索,利用了"新出現的入度為0的點必定是由邊的刪除造成的"這一特性,對頂點進行遍歷,較之自己的演算法邏輯更優 
		使用了cnt計數器與頂點總數n比較來判定是否頂點皆已刪除,較之自己的演算法邏輯更優 
		*/
		while(!q.empty()){
			int nowP=q.front(); 
			q.pop();//del the vex
			cnt++;
			for (int i=0;i<graph.edge[nowP].size();i++){//traverse the edges & reduce inDegree
				int nextNode=graph.edge[nowP][i].nextNode;
				inDegree[nextNode]--;
				if (inDegree[nextNode]==0)
					q.push(nextNode);
			}
			graph.edge[nowP].clear();//del the edges
		}
		//output
		cout<<(cnt==graph.graphSize?"Yes":"No")<<endl;
	}
	return true;
}