[NOIP2011普及组]瑞士轮 JAVA实现

时间:2023-04-12 17:20:58
题目描述

2*N名编号为1~2N的选手共进行R轮比赛。每轮比赛开始前,以及所有比赛结束后,都会按照总分从高到低对选手进行一次排名。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。

每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1名和第2名、第3名和第4名、……、第2K-1名和第2K名、……、第2N-1名和第2N名,各进行 一场比赛。每场比赛胜者得 1分,负者得0分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。

现给定每个选手的初始分数及其实力值,试计算在R轮比赛过后,排名第Q的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。

输入格式

输入的第一行是三个正整数N、R、Q,每两个数之间用一个空格隔开,表示有2*N名选手、R轮比赛,以及我们关心的名次Q。

第二行是2*N个非负整数s1,s2,…,s2N,每两个数之间用一个空格隔开,其中si表示编号为i的选手的初始分数。

第三行是2*N个正整数w1,w2,…,w2N,每两个数之间用一个空格隔开,其中wi表示编号为i的选手的实力值。

输出格式

输出只有一行,包含一个整数,即R轮比赛结束后,排名第Q的选手的编号。

样例输入

2 4 2
7 6 6 7
10 5 20 15

样例输出

1

两种java代码解决

1、每轮比赛得出新的积分后通过冒泡排序或快速排序得出新的排名(一维数组存储选手信息)

 package xpc.sort;

 import java.util.Scanner;

 /**
* 瑞士轮问题实现
*
* @author xpc
*
*/
public class RuiShiLun { public static void main(String[] args) {
RuiShiLun obj = new RuiShiLun();
int no[];//每个选手的编号,顺序按名次
int s[];
int w[];
Scanner scanner = new Scanner(System.in);
System.out.println("请输入N R Q");
String str = scanner.nextLine();
String [] temp = str.split(" ");
int n = Integer.parseInt(temp[0]);
int r = Integer.parseInt(temp[1]);
int q = Integer.parseInt(temp[2]);
no = new int[2*n];
s = new int[2*n];
w = new int[2*n];
System.out.println("请输入对应编号选手初始分数:");
str = scanner.nextLine();
temp = str.split(" ");
for(int i = 0; i < temp.length;i++){
s[i] = Integer.parseInt(temp[i]);
no[i] = i+1;
}
System.out.println("请输入对应编号选手实力值:");
str = scanner.nextLine();
temp = str.split(" ");
for(int i = 0; i < w.length;i++){
w[i] = Integer.parseInt(temp[i]);
}
// int no[] = new int[]{1,2,3,4};//每个选手的编号,顺序按名次
// int s[] = new int[]{7,6,6,7};
// int w[] = new int[]{10,5,20,15};
// int n = 2;
// int r = 4;
// int q = 2;
int i = 0;
while(i < r){
i++;
System.out.println("第"+i+"轮比赛后:");
obj.sigleAfter(no,s,w);
for(int t = 0 ; t < s.length;t++){
System.out.println("第"+(t+1)+"名:"+no[t]+",分数:"+s[t]);
}
}
System.out.println("第"+r+"轮后排名第"+q+"的编号是:"+no[q-1]);
} public void sigleAfter(int no[],int s[],int w[]){
for(int i = 0; i < s.length-1; i+=2){
if(w[i] > w[i+1]){
s[i] ++;
}else{
s[i+1]++;
}
}
//选择排序
// chosesort(s, no, w);
//快排
quicksort(s,no,w,0,s.length-1);
} public void chosesort(int s[],int []no,int w[]){
for(int i = 0; i < s.length-1; i++){
for(int j = i+1; j< s.length;j++){
if(s[i] < s[j]){
int temp = s[i];
s[i] = s[j];
s[j] = temp; temp = no[i];
no[i] = no[j];
no[j] = temp; temp = w[i];
w[i] = w[j];
w[j] = temp;
}else if(s[i] == s[j]){
if(no[i] > no[j]){
int temp = s[i];
s[i] = s[j];
s[j] = temp; temp = no[i];
no[i] = no[j];
no[j] = temp; temp = w[i];
w[i] = w[j];
w[j] = temp;
}
}
}
}
} /**
* 三分取中值策略
* @param left
* @param right
* @return
*/
public int median3(int s[],int []no,int w[],int left,int right){
int center = (left+right)/2;
if(s[left] < s[center]){
swapReference(no,s,w, center, left);
}
if(s[center] < s[right]){
swapReference(no,s,w, right, center);
}
if(s[left] < s[center]){
swapReference(no,s,w, left, center);
}
if(left+1 > right){
swapReference(no,s,w, center, right);
}
return s[right];
} public void quicksort(int []s,int no[],int w[],int left,int right){
if(left < right){
int pivot = median3(s,no,w,left,right);
if(right - left > 1){
int i = left;
int j = right;
while(true){//大的放左边,小的放右边
while(s[++i] > pivot){
if(s[i] == pivot && no[i] >= no[right]){//积分相同,i的编号较大所以需要移到右边
break;
}
}
while(s[--j] <= pivot){
if(s[j] == pivot && no[j] <= no[right]){//积分相同,i的编号较小所以需要移到左边
break;
}
}
if(i < j){
swapReference(s,no,w, i, j);
}else{
break;
}
}
swapReference(s,no,w, i, right);
quicksort(s,no,w, left,i-1);
quicksort(s,no,w, i+1, right);
} }
} /**
* 互换数组中的元素
* @param a
* @param i
* @param j
*/
private void swapReference(int []no ,int []s,int w[],int i,int j){
int temp = no[i];
no[i] = no[j];
no[j] = temp; temp = s[i];
s[i] = s[j];
s[j] = temp; temp = w[i];
w[i] = w[j];
w[j] = temp;
} }

2、除第一次排序通过快速排序将积分重排,后面每轮将选手分为胜者组合败者组两组,通过归并合在一起(二维数组存储选手信息)

package xpc.sort;

public class RuiShiLun2 {

    public static void main(String[] args) {
RuiShiLun2 sort = new RuiShiLun2();
int n = 2;
int r = 4;
int q = 2;
// int no[] = new int[]{1,2,3,4};//每个选手的编号,顺序按名次
// int s[] = new int[]{7,6,6,7};
// int w[] = new int[]{10,5,20,15};
int ans [][] = new int[2*n][3];//0:积分 1:实力 2:编号
ans[0][0] = 7;
ans[0][1] = 10;
ans[0][2] = 1; ans[1][0] = 6;
ans[1][1] = 5;
ans[1][2] = 2; ans[2][0] = 6;
ans[2][1] = 20;
ans[2][2] = 3; ans[3][0] = 7;
ans[3][1] = 15;
ans[3][2] = 4;
int a[][] = new int [n][3];//胜者组
int b[][] = new int [n][3];//败者组 sort.sigleAfter(a, b, ans); int r1 = 1;
sort.chosesort(ans);
System.out.println("第"+r1+"轮后排名");
for(int i = 0 ; i < ans.length;i++){
System.out.println("第"+(i+1)+"名:"+ans[i][2]+"-"+ans[i][0]+"-"+ans[i][1]);
}
while(r > 1 && r1 <r){
r1++;
sort.sigleAfter(a, b, ans);
sort.mergeArray(a, b, ans);
System.out.println("第"+r1+"轮后排名");
for(int i = 0 ; i < ans.length;i++){
System.out.println("第"+(i+1)+"名:"+ans[i][2]+"-"+ans[i][0]+"-"+ans[i][1]);
}
}
System.out.println("第"+r+"轮后排名第"+q+"的编号是:"+ans[q-1][2]);
}
private void sigleAfter(int a[][],int b[][],int ans[][]){
int j = 0;
for(int i = 0; i < ans.length-1; i+=2){
if(ans[i][1] > ans[i+1][1]){
ans[i][0]++;
a[j] = ans[i];
b[j] = ans[i+1];
}else{
ans[i+1][0]++;
a[j] = ans[i+1];
b[j] = ans[i];
}
j++;
}
} /**
*
* 选择排序
* @param s
* @param no
* @param w
*/
public void chosesort(int ans[][]){
for(int i = 0; i < ans.length-1; i++){
for(int j = i+1; j< ans.length;j++){
if(ans[i][0] < ans[j][0]){
int[] temp = ans[i];
ans[i] = ans[j];
ans[j] = temp; }else if(ans[i][0] == ans[j][0]){
if(ans[i][2] > ans[j][2]){
int []temp = ans[i];
ans[i] = ans[j];
ans[j] = temp;
}
}
}
}
} /**
* 胜者组败者组做归并
* @param a
* @param b
* @param ans
*/
private void mergeArray(int a[][],int b[][],int ans[][]){
int k = 0;
int t = 0;
int m = 0;
while(t<a.length && m<b.length){
if(a[t][0] > b[m][0]){
ans[k++] = a[t++];
}else{
if(a[t][0] == b[m][0] && a[t][2] < b[m][2]){
//积分相同编号小的往前排
ans[k++] = a[t++];
continue;
}
ans[k++] = b[m++];
}
}
while(t<a.length){
ans[k++] = a[t++];
}
while(m<b.length){
ans[k++] = b[m++];
}
}
}