7-2 The Judger (25分)
A game of numbers has the following rules: at the beginning, two distinct positive integers are given by the judge. Then each player in turn must give a number to the judge. The number must be the difference of two numbers that are previously given, and must not be duplicated to any of the existed numbers. The game will run for several rounds. The one who gives a duplicate number or even a wrong number will be kicked out.
Your job is to write a judger program to judge the players' numbers and to determine the final winners.
Input Specification:
Each input file contains one test case. For each case, the first line gives two distinct positive integers to begin with. Both numbers are in $[1,10^5]$.
In the second line, two numbers are given: N (2≤N≤10), the number of players, and $M (2≤M≤10^3)$, the number of rounds.
Then N lines follow, each contains M positive integers. The i-th line corresponds to the i-th player (i=1,⋯,N). The game is to start from the 1st player giving his/her 1st number, followed by everybody else giving their 1st numbers in the 1st round; then everyone give their 2nd numbers in the 2nd round, and so on so forth.
Output Specification:
If the i
-th player is kicked out in the k
-th round, print in a line Round #k: i is out.
. The rest of the numbers given by the one who is out of the game will be ignored. If more than one player is out in the same round, print them in increasing order of their indices. When the game is over, print in the last line Winner(s): W1 W2 ... Wn
, where W1 ... Wn
are the indices of the winners in increasing order. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the beginning or the end of the line. If there is no winner, print No winner.
instead.
Sample Input 1:
101 42
4 5
59 34 67 9 7
17 9 8 50 7
25 92 43 26 37
76 51 1 41 40
Sample Output 1:
Round #4: 1 is out.
Round #5: 3 is out.
Winner(s): 2 4
Sample Input 2:
42 101
4 5
59 34 67 9 7
17 9 18 50 49
25 92 58 1 39
102 32 2 6 41
Sample Output 2:
Round #1: 4 is out.
Round #3: 2 is out.
Round #4: 1 is out.
Round #5: 3 is out.
No winner.
题目限制:
题目大意:
现在有N个玩家一起玩一个游戏,开始会先给出2个数字,游戏进行M轮,每一轮将会从第一个玩家开始给出一个数字,直到最后一个,给出的数字如果之前有人给出过,那么说明给的是duplicate number当前人被淘汰,或者给出的数字无法在所有已经给出的数字中找到2个数的差等于该数,说明该数是wrong number,该人被淘汰,否则当前玩家晋级,同时该数字记录为已经给出的数字,被淘汰的玩家在下一轮比赛中不再参与比较。现要求输出每一轮淘汰的玩家的编号和比赛结束的时候赢家的编号,如果没有赢家输出No winner.
算法思路:
该题题意需要好好理解,关键是这句话
The game is to start from the 1st player giving his/her 1st number,followed by everybody else giving their 1st numbers in the 1st round; then everyone give their 2nd numbers in the 2nd round,and so on so forth.
这句话给出了游戏的规则,意思是每一轮比赛,从第一个选手开始给出一个数字,进行比较是否出现是否可以在已经给出的数字中查找到2数的差值为该数,该过程结束后,才进行下一个玩家的判别,对应上例子就是定住一列,从上往下看,每次出队一个数字,然后比较,如果没有被淘汰,该数字会添加到已经存在的集合中,作为下一次的比较查找过程集合的一部分。
明白这一点后,思路就清晰了,我们使用exist_numbers存储所有当前已经出现过的数字,isExist标记已经存在的数字,使用hasDifference(n)函数判断是否存在exist_numbers中的两个数字的差为n,判断的思路就是通过假设a,b为exist_numbers中的两个数,那么判断a-b=n或者b-a=n,其等价形式为a=b+n或者b=a+n,直接判断是否存在一个数字a在exist_numbers中,a+n是否也在exist_numbers中就行了,代码如下:
// 判断是否存在exist_numbers中的两个数字的差为n
bool hasDifference(int n){
for(int num:exist_numbers){
if(isExist[num+n]){
// 存在
return true;
}
}
return false;
}
然后我们使用outPlayer数组存储在当前轮所有被淘汰的人,out标记每一个淘汰的玩家,遍历每一个没有被淘汰的玩家,使用isOut标记当前玩家是否淘汰,其规则就是isOut = isExist[number[i][j]]||!hasDifference(number[i][j])(number[i][j]表示第i个player在第j轮出的数字),
只要isOut为true,说明该玩家被淘汰,将其加入到outPlayer中,并将当前人的淘汰标记设置为true(out[i] = true)
,否则该玩家晋级,将其数字添加到exist_numbers
集合中,并标记该数字以及存在。在当前轮次比较完毕后,就输出所有的被淘汰的玩家。如果比赛结束,就遍历out数组,将所有没有被淘汰的玩家添加到winners
集合中,最后如果winners
不为空,输出每一个玩家,否则输出No winner.
注意点:
- 1、
exist_numbers
使用vector
有可能会导致测试点5运行超时,使用unordered_set
和set
就可以,但是使用vector多提交几次也可以通过 - 2、测试点2和5考察多人淘汰的情况,也就是有多人淘汰的时候,是每次输出一行
Round #k: i is out.
而不是将所有人集中在一起输出,比如Round #k: i j is out.
就是错误的 - 3、当前玩家如果被淘汰,其对应的数字不能添加到exist_numbers,也就是算在已经出现的数字集合中,换句话说,在已经出现的数字集合中,一定是任意2数的差值还在该集合中,测试点6考察。
提交结果:
AC代码:
#include
#include
#include
#include
using namespace std;
int number[15][1005];// number[i][j]表示第i个player在第j轮出的数字
unordered_set exist_numbers;// 所有当前已经出现过的合法数字,使用vector有可能会超时,但是会出现通过的情况
unordered_map isExist;//标记已经存在的数字
bool out[20];// 标记每一个淘汰的玩家
// 判断是否存在exist_numbers中的两个数字的差为n
bool hasDifference(int n){
for(int num:exist_numbers){
if(isExist[num+n]){
// 存在
return true;
}
}
return false;
}
int main(){
int a,b;
scanf("%d %d",&a,&b);
exist_numbers.insert(a);
exist_numbers.insert(b);
isExist[a] = isExist[b] = true;
int N,M;// 玩家数目和轮次
scanf("%d %d",&N,&M);
for(int i=1;i<=N;++i){
for(int j=1;j<=M;++j){
scanf("%d",&number[i][j]);
}
}
// 开始比赛
for(int j=1;j<=M;++j){// 每一轮
vector outPlayer;//在当前轮所有被淘汰的人
for(int i=1;i<=N;++i){//每一个玩家
if(!out[i]){
bool isOut = isExist[number[i][j]]||!hasDifference(number[i][j]);//已经存在过了或者没有差值存在为true
if(isOut){
// 将对应的玩家添加到淘汰队列中
outPlayer.push_back(i);
out[i] = true;
} else{// 测试点6考察,只有在当前用户没有被淘汰的时候就将该人的数字添加到集合中
//将当前数字加入到exist_numbers中,
exist_numbers.insert(number[i][j]);
isExist[number[i][j]] = true;
}
}
}
// 当前轮次比较完毕
for(int item:outPlayer){
// 输出被淘汰的人,如果没有就不会输出
printf("Round #%d: %d is out.\n",j,item);
}
}
// 遍历所有的人,判断是否还有赢家
vector winners;
for(int i=1;i<=N;++i){
if(!out[i]){
winners.push_back(i);
}
}
if(!winners.empty()){
printf("Winner(s):");
for(int winner:winners){
printf(" %d",winner);
}
}else{
printf("No winner.");
}
return 0;
}