Problem Description
有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。
球赛的规则如下:
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。
球赛的规则如下:
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。
Input
输入含有一些选手群,每群选手都以一个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以一对选手名字(中间隔一空格)表示,前者战胜后者。如果n为0,则表示输入结束。
Output
对于每个选手群,若你判断出产生了冠军,则在一行中输出“Yes”,否则在一行中输出“No”。
Sample Input
3 Alice Bob Smith John Alice Smith 5 a c c d d e b e a d 0
Sample Output
Yes No
思路:第一种方法,将赢得人放在一组,输的人放在另一组,看看赢得组中没有出现在输的一组中的个数,若为1,则表示可以产生冠军,否则不可以(这种方法可以在杭电ac)
第二种方法,把每个人看做一个结点,统计每个结点的入度,看所有结点中入度为0的个数有多少个,若为1,则表示可以产生冠军,否则不可以(这种方法不能ac,超内存,当练练拓扑排序)
方法一:
package search.topology;
import java.util.Scanner;
public class P2094 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n=sc.nextInt();
if(n==0){
break;
}
Containter winners=new Containter(n);//将赢得人放在一个容器中,此容器不能重复存放同一人
Containter losers=new Containter(n);//将输的人放在一个容器中
for(int i=0;i<n;i++){
winners.add(sc.next());
losers.add(sc.next());
}
int count=0;
boolean flag;
for(int i=0;i<winners.num;i++){
flag=true;
for(int j=0;j<losers.num;j++){
if(winners.contain[i].compareTo(losers.contain[j])==0){//判断输的人的容器中是否有赢的人
flag=false;
break;
}
}
if(flag){//若该赢的人没有出现在输的人中,则可以看做冠军
count++;
}
}
if(count==1){//当可以看做冠军的人数为1时,则表示可以产生冠军
System.out.println("Yes");
}else{
System.out.println("No");
}
}
}
}
class Containter{
String[] contain;
int num=0;
public Containter(int n) {
this.contain=new String[n];
}
public void add(String str){
if(isExist(str)){//判断是否已经存在容器中了
return ;
}
contain[num++]=str;
}
public boolean isExist(String str){
for(int i=0;i<num;i++){
if(contain[i].compareTo(str)==0){
return true;
}
}
return false;
}
}
方法二:
package search.topology;
import java.util.Scanner;
public class P2094_2 {
public static int num;//统计人数
public static String[] str;//存放人名
public static int[][] arc;//记录谁赢了谁
public static int[] degree;//存放每个人输的次数,也就是每个结点的入度
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n;
while(sc.hasNext()){
n=sc.nextInt();
if(n==0){
break;
}
int x,y;
num=0;
arc=new int[1000][1000];
degree=new int[1000];
str=new String[n*2];
for(int i=0;i<n;i++){//因为不会用字符串做索引,所以将字符串转化int代替
x=isExist(sc.next());
y=isExist(sc.next());
arc[x][y]=1;
degree[y]++;
}
topoSort();
}
}
private static void topoSort() {
int count=0;
for(int i=0;i<num;i++){
if(degree[i]==0){
count++;
}
}
if(count==1){
System.out.println("Yes");
}else{
System.out.println("No");
}
}
private static int isExist(String s) {//若存在这个人了,就返回这个人的序号,若没有,则新添这个人的序号
for(int i=0;i<num;i++){
if(str[i].compareTo(s)==0){
return i;
}
}
str[num++]=s;
return num-1;
}
}