时间限制:1s 内存限制:32MB

题目描述

球赛规则:如果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

题目分析

  • 该题可以联想到用拓扑排序解决,选手对应节点,胜负关系对应为节点之间的有向边,可以产生冠军的情况即为全图中入度为零的点唯一。但与普通的拓扑排序不同的是,需要将输入的选手姓名映射为节点编号,需要标准对象map。
  • map很好的完成从string到int的映射。map的用法:
map<string, int> M; //定义一个完成从string到int映射的map
M.clear(); //对map中的映射关系清空
M.find(a); //确定map中是否保存string对象a的映射,若没有返回M.end()
M[b] = idx; //若map中不存在string对象b的映射,则定义其映射为idx
idxa = M[a]; //若map中存在string对象a的映射,则读出该映射
  • map的内部实现是一棵红黑树。

代码

#include <iostream>
#include <map>
#include <string>
#include <string.h>
using namespace std;

map<string, int> M; //定义一个完成从string到int映射的map
int in[2002]; //保存入度

int main() {
	//抽象为拓扑排序,冠军是图中入度为0的点,但要将输入的选手姓名 映射 为节点编号(使用map)
	int n;
	while(scanf("%d", &n) != EOF && n != 0) {
		memset(in, 0, sizeof(in));
		M.clear(); //对map中的映射关系清空
		int idx = 0; //下一个被映射的数字
		for(int i = 0; i < n; i++) {
			char str1[50], str2[50];
			cin >> str1 >> str2;
			string a = str1, b = str2; //将字符串保存至string中
			int idxa, idxb;
			if(M.find(a) == M.end()) { //若map中尚无对该a的映射
				idxa = idx;
				M[a] = idx++; //设定映射为idx,并递增idx
			} else
				idxa = M[a]; //直接读出该映射
			if(M.find(b) == M.end()) {
				idxb = idx;
				M[b] = idx++;
			} else
				idxb = M[b];
			in[idxb]++; //b的入度加一
		}
		int cnt = 0;
		for(int i = 0; i < idx; i++) {
			if(in[i] == 0)
				cnt++;
		}
		puts(cnt==1 ? "Yes" : "No");
	}
	return 0;
}

运行结果

王道机试指南NO.17产生冠军map模板类

相关文章:

  • 2021-05-18
  • 2021-08-25
  • 2022-01-06
  • 2022-12-23
  • 2022-01-21
  • 2022-01-02
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-03-05
  • 2021-12-28
  • 2022-12-23
  • 2022-12-23
  • 2021-12-27
  • 2021-06-03
相关资源
相似解决方案