题目描述:洛谷p1309瑞士轮题目描述放在链接里,忘记题目描述的同学可以回去复习一下嗷。
思路 看了好多题解,都是硬往归并排序上靠,但是为什么是归并排序呢,看了好多篇文章都没有看懂,直到我手动的去模拟了一次,所以这道题它并不是单纯的归并排序,而是模拟归并排序(如果不会归并排序的小伙伴,可以看一下我的博客归并排序)。为什么这么说呢?因为每进行一场比赛,都要根据选手实力分出胜者组和败者组,然后我们再将胜者组和败者组根据分数大小来排成新的序列,依次类推。是不是突然感觉像归并排序中的先二分分裂,再回溯合并的过程,二分分裂是单纯的使用序列的长度进行分裂,但是在这道题中我们需要用选所受的实力,分为胜败者组,所以我觉得这道题的本质仍然是模拟,模拟的像归并排序,需要注意的是第一次我们得sort一下,因为第一场的顺序是我们没法提前预知的。
注意:不能够直接进行一轮比赛去sort()一次,时间会爆炸的,sort()对随机数组的排序比较快速且重复较少。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct node
{
int num;
int s;
int w;
};
node vis[N],tmp[N],win[N],lose[N];
int n,r,q;
bool cmp(node s1,node s2)
{
if(s1.s==s2.s)return s1.num<s2.num;
else return s1.s>s2.s;
}
void solve()
{
int wi=1,li=1;
for(int i=1;i<=n*2;i=i+2)
{
if(vis[i].w>vis[i+1].w)
{
vis[i].s++;
win[wi++]=vis[i];
lose[li++]=vis[i+1];
}
else
{
vis[i+1].s++;
win[wi++]=vis[i+1];
lose[li++]=vis[i];
}
}
int i=1,j=1,k=1;
while(i<wi&&j<li)
{
if(cmp(win[i],lose[j]))
{
vis[k++]=win[i++];
}
else vis[k++]=lose[j++];
}
while(i<wi)vis[k++]=win[i++];
while(j<li)vis[k++]=lose[j++];
// for(i=1;i<=n;i++)vis[i]=tmp[i];
}
int main()
{
cin>>n>>r>>q;
for(int i=1;i<=n*2;i++)
{
cin>>vis[i].s;
vis[i].num=i;
}
for(int i=1;i<=n*2;i++)cin>>vis[i].w;
sort(vis+1,vis+1+2*n,cmp);
for(int i=1;i<=r;i++)
{
solve();
}
//for(int i=1;i<=n*2;i++)printf("%d***%d\n",vis[i].num,vis[i].s);
//printf("\n");
printf("%d",vis[q].num);
return 0;
}