拓扑排序--巡回赛

巡回赛

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述
世界拳击协会(WBA)是历史最悠久的世界性拳击组织,孕育了众多的世界冠军,尤其是重量级,几乎造就了大家耳熟能详的所有伟大的拳王。阿里、弗雷泽、福尔曼被称为“70年代重量级拳坛 三巨头”,是当之无愧的拳王,他们的得到的金腰带都刻有 WBA 字样。为庆贺世界拳击协会成立 50 周年,WBA 主席门多萨邀请 N 名拳击手进行了 M 场巡回比赛,每场比赛均可分出胜负,比赛过后组委会要对 N 名选手进行排序,对于每名拳手,必须满足该拳手所战胜过的对手全部排在其后才能对该排名满意。
现给出 M 场比赛的胜负关系,请你帮组委会决定是否能够唯一确定这样的排名,使得所有的拳击手都满意,若能唯一确定则输出最终排名。
输入
第一行给出测试数据的组数 T(0<T<30),对于每组测试数据,首先依次给出N(1<=N<=26),M(0<=M<=1000)分别表示拳手数和比赛数,拳手的姓名依次为从 A开始的前 N 个大写字母,接下 M 行给出每场比赛的比赛结果,每行由两个大写字母组成,两者之间有一空格。
如 “A B”则表示在某场比赛中 A 战胜了 B。
输出
对于每组测试,若不存在唯一的排名序列则单行输出“No Answer”,若存在则按排名从高至低输出拳手的名字。
样例输入
3
4 4
A B
A C
B C
C D
4 4
A B
A C
B D
C D
3 3
A B
B A
A C
样例输出
ABCD
No Answer
No Answer
来源
山东大学 ACM/ICPC 校赛高年级组试题 2012
上传者

ACM_李如兵



拓扑排序,把一个图的所有节点排序,使每一条有向边(u, v)对应的u都排在v之前。充要条件,图中不存在有向环。故是对有向无环DAG图而言的概念

。此题是把赢家到输家当做一条有向边,进行拓扑排序,若存在排序后的唯一序列,则输出。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<queue>

using namespace std;

vector <char>g[100];
char sorted[30];
int n, m, indegree[100];

void init();
void read();
void topsort();

int main(){
	int T, i, j;
	char cur;
	scanf("%d", &T);
	while(T--){
		scanf("%d %d", &n, &m);
		getchar();
		init();
		read();
		memset(indegree, 0, sizeof(indegree));
		for(i = 'A'; i <= n + 'A' - 1; i++){
			for(j = 0; j < g[i].size(); j++){
				cur = g[i][j];
				indegree[cur]++;
			}
		}
		topsort();
	}
	return 0;
}

void topsort(){
	int i, j, flag, num;
	char v, cur;
	queue <char>Q;
	//先计算每个节点的入度
	flag = 0; num = 0;
	for(i = 'A'; i <= n + 'A' - 1; i++){//注意是循环到n + A - 1,不是n + A
		if(indegree[i] == 0){
			Q.push(i);
			num++;
		}
	}
	if(num > 1){
		flag = 1;
		printf("No Answer\n");
		return ;
	}

	j = 0;
	while(!Q.empty()){
		j += 1;
		cur = Q.front();
		Q.pop();
		sorted[j] = cur; num = 0;
		for(i = 0; i < g[cur].size(); i++){
			v = g[cur][i];
			indegree[v]--;
			if(indegree[v] == 0){
				Q.push(v);
				num++;//记录队列里的元素个数
			}
		}
		if(num > 1)
			flag = 1;//若队列里同时有两个元素,说明拓扑排序的序列不唯一,标记
	}

	if(j == n && !flag){
		for(i = 1; i <= j; i++)
			printf("%c", sorted[i]);
		printf("\n");
	}
	else
		printf("No Answer\n");
}

void read(){
	int i;
	char a, b;
	for(i = 0; i < m; i++){
		scanf("%c %c", &a, &b);
		getchar();
		g[a].push_back(b);//让g数组的A到Z即65到90的位置保存字符
	}
}

void init(){
	int i;
	for(i = 'A'; i <= n + 'A' - 1; i++)
		g[i].clear();
}        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值