九度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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值