这道题厉害了。= =想不明白
算法分析:
由于这里的优先关系具有传递性,故可利用有向图表示优先关系:“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;
}