洛谷 P1309 瑞士轮 归并排序

题目背景

在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为

公平,偶然性较低,但比赛过程往往十分冗长。 本题中介绍的瑞士轮赛制,因最早使用于18951895年在瑞士举办的国际象棋比赛而得名。它可以看作是淘汰赛与循环赛的折中,既保证了比赛的稳定性,又能使赛程不至于过长。

 题目描述

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, …, s 2N ,每两个数之间用一个空格隔开,其中 si 表示编号为 i 的选手的初始分数。 第三行是 2×N 个正整数 w1 , w2 ,

w2N,每两个数之间用一个空格隔开,其中 wi表示编号为ii 的选手的实力值。
输出格式
一个整数,即 R 轮比赛结束后,排名第 Q 的选手的编号。
输入输出样例
输入 #1                       输出 #1 
2 4 2                         1
7 6 6 7 
10 5 20 15 

  

题解
  首先是极弱的 40 分 题 解 ,40分就是常规思路 —— 设置结构体 利用对 < 号的重载 重写 sort 函数 关键性的一点就是在于 经过一轮下来 排名为

第 i 和 第 i+1 名都需要比赛 ,因此 设置 两个 for 循环 在 第 2 个 for 循环中 以 2 为单位 进行增减 并进行重新排序 这样下来就可以比较相邻

分数的两人的实力。

  但是 由于 在 for 循环中 使用了 sort 函数 导致出现的一个问题 也就是 40分的问题 出现了大量的 RE 也就是说 运行时间爆炸 思考之后 这是因

为 sort() 本质上是一个快排 这导致 在每次的 for 循环中 前后两个值 都进行了比较与更新 也就是说是更新 2*N*R 次 但是在这道题中 每次只有 winner

才需要进行修改值 即 更新 (2*N*R)/2 次 这个时间限制肯定会无限爆炸。

  但是 极弱 在看大佬的题解之前 完全没有想到 使用 归并 排序。
  
  本题实际上是 winner 的 分数 +1,loser的分数不变,两者都保持一个 有序 的状态 因此 可以 将两个有序表 进行 归并 操作
  
  归并排序 def: ① 建立在归并操作上 ② 合并已有序的子序列 ③采用分治法
  而STL库中 直接提供 merge()函数 实现 2-路归并排序 操作
  
  merge(first1,last1,first2,last2,result,compare);
  
  // merge(第1个容器的首迭代器,第1个容器的尾迭代器,第2个容器的首迭代器,第2个容器的尾迭代器,存放结果的容器,比较函数);  
  
  在尝试归并排序后,由于我是在40分代码的基础上进行的修改,有一个很坑的地方忘记了,忘记修改p[]——即归并后的数组的数组范围,导致出现了70分。

40分代码

#include<iostream> #include<algorithm> using namespace std; int n,r,q,j=0; struct player{ int start;  //表示初始分数 int power;  //表示权重 int no;    //表示其序号 }p[100010]; bool cmp(player p1,player p2){ if(p1.start>p2.start){ return p1.start>p2.start; } else if(p1.start==p2.start){ return p1.no<p2.no; } else return 0; } int main(){ cin>>n>>r>>q; for(int i=1;i<=(2*n);i++){ cin>>p[i].start; p[i].no=i; } for(int i=1;i<=(2*n);i++){ cin>>p[i].power; } for(int j=1;j<=r;j++){         for(int i=1;i<=2*n;i=i+2){ if(p[i].power>p[i+1].power){ p[i].start++; } else p[i+1].start++; } sort(p+1,p+2*n+1,cmp); } cout<<p[q].no<<endl; return 0; }

 AC代码

 1 #include<iostream>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 
 6 int n,r,q,j=0;
 7 
 8 struct player{
 9     int start;
10     int power;
11     int no;
12 }p[200010],winner[100010],loser[100010];
13 
14 bool cmp(player p1,player p2){
15     if(p1.start>p2.start){
16         return p1.start>p2.start;
17     }
18     else if(p1.start==p2.start){
19         return p1.no<p2.no;
20     }
21     else return 0;
22 }
23 
24 int main(){
25     cin>>n>>r>>q;
26     for(int i=1;i<=(2*n);i++){
27         cin>>p[i].start;
28         p[i].no=i;
29     }
30     for(int i=1;i<=(2*n);i++){
31         cin>>p[i].power;
32     }
33     sort(p+1,p+2*n+1,cmp);    
34     
35     for(int j=1;j<=r;j++){
36         int ans=0,pos=0;
37         for(int i=1;i<=2*n;i=i+2){
38             if(p[i].power>p[i+1].power){       
39                 winner[++ans]=p[i];
40                 winner[ans].start++;
41                 loser[++pos]=p[i+1];
42             }
43             else{
44                 winner[++ans]=p[i+1];
45                 winner[ans].start++;
46                 loser[++pos]=p[i];
47             } 
48         }
49         merge(winner+1,winner+ans+1,loser+1,loser+pos+1,p+1,cmp);   
50     } 
51     cout<<p[q].no<<endl;    
52     return 0;
53 } 

转载于:https://www.cnblogs.com/jjjjjjy/p/11254215.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值