洛谷 P1309 瑞士轮(归并)

题目链接:https://www.luogu.org/problemnew/show/P1309
题意:一共2n个人(有一个初始分数)进行k轮比赛,每轮比赛按当前得分排出名次,然后比赛按照第1名和第2名,第3和第4…第2n-12n进行(实力各不相同且实力大的总能获胜)。获胜方加一分,失败方分数不变。
思路:
一开始想在每轮比赛前用sort排序,算了下复杂度大概O(n*(n*logn)+n*k),显然不行。
后来想了下快排操作次数太多了,针对随机数列还行,这种就有点浪费了,于是想到了用类似与归并排序的思想,另外设置两个数组vic[]los[] 存胜者和败者,然后只需对vic[i],los[j]比较分数大小大的放进总数组里就可以了
当然我使用结构体存数据。
代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
struct Competitor{
    int num;
    int mark;
}p[200003],vic[100002],los[100002];
int w[200001];//每个人的实力
bool cmp(Competitor a,Competitor b){//定义比较函数
    if(a.mark==b.mark)//分数相同编号小的在前
        return a.num<b.num;
    return a.mark>b.mark;
}
void Merge(int e){
    int i=1,j=1,k=1;
    while(i<=e&&j<=e){
        if(vic[i].mark<los[j].mark||vic[i].mark==los[j].mark&&vic[i].num>los[j].num){
            p[k].mark=los[j].mark;//往p里放
            p[k++].num=los[j++].num;
        }
        else{
            p[k].mark=vic[i].mark;
            p[k++].num=vic[i++].num;
        }
    }
    while(i<=e){
        p[k].mark=vic[i].mark;//有多的接着往p里放
        p[k].num=vic[i].num;
        k++;i++;
    }
    while(j<=e){
        p[k].mark=los[j].mark;
        p[k].num=los[j].num;
        k++;j++;
    }
}
int main(){
    int n,r,q;
    scanf("%d %d %d",&n,&r,&q);
    for(int i=1;i<=2*n;i++){
        scanf("%d",&p[i].mark);
        p[i].num=i;//读入
    }
    for(int i=1;i<=2*n;i++)
        scanf("%d",&w[i]);//读入
    sort(p+1,p+1+2*n,cmp);
    for(int i=1;i<=r;i++){
        int t=1;
        for(int j=1;j<=2*n;j+=2){//分配胜者、败者数组
            if(w[p[j].num]>w[p[j+1].num]){
                vic[t].mark=p[j].mark+1;
                vic[t].num=p[j].num;
                los[t].mark=p[j+1].mark;
                los[t].num=p[j+1].num;
                t++;
            }
            else{
                vic[t].mark=p[j+1].mark+1;
                vic[t].num=p[j+1].num;
                los[t].mark=p[j].mark;
                los[t].num=p[j].num;
                t++;
            }
        }
        Merge(n);
    }
    //for(int i=1;i<=2*n;i++)
        printf("%d\n",p[q].num);//输出排名为q选手的编号
return 0;
}

总结:排序中的一些思想很重要。

猜你喜欢

转载自blog.csdn.net/yczhaoxun/article/details/79874058
今日推荐