zoukankan      html  css  js  c++  java
  • 【洛谷p1309】瑞士轮

    因为太菜不会写P1310 表达式的值,就只能过来水两篇博客啦qwq

    另外这个题我是开o2才过的(虽然是写了归并排序)(可能我太菜写的归并不是还可以“剪枝”吧qwq)哎,果真还是太菜啦qwq

    所以准备写归并然后去题解学习正确的不用开O2就可以过的算法;

    咱好像忘记添加链接了qwq:

    瑞士轮【题目链接】


    其实这个题打眼一看可以直接sort来做,但是这个题用sort还是太慢了qwq、开o2都只有70pts,因此这是逼着我重新复习一遍归并排序啊qwq:

    About归并:

    注意归并排序要开一个辅助数组f[k],k从1开始~n记录了排好序的数组,然后为了保证每次排序都有效所以最后要重新将f数组的值赋给a数组,归并排序的思想是把一个排序区间分成两个大概等长(因为会出现奇数个元素所以并不是一定完全等长)的区间,然后接着再分,直到每个区间都只剩一个元素,接下来合并两个区间,分别设指针i和j指向要合并的两个区间的头,然后进行比较,如果a[i]<a[j](假设从小到大排),那么令i++,同时k++,f[k]=a[i];否则的话,令j++,同时k++,f[k]=a[j];结束的条件是i>mid或j>end(排序的末端点),然后将i之后和j之后没有进行比较的数(因为归并是从最小区间(1)开始排序,因此当我们排一个区间长度时,它的左边部分和右边部分已经都是有序的啦)复制到f数组中。

    CODE:(归并)

    void msort(int str,int end){//from big to smasll
        if(str==end) return;
        int mid=(str+end)>>1;
        msort(str,mid);
        msort(mid+1,end);
        int i=str,j=mid+1,k=str;
        while(i<=mid&&j<=end){
            if(p[i]>p[j]){
                r1[k]=p[i];
                k++;i++;
            }
            else {
                r1[k]=p[j];
                k++;j++;
            }
        }
        while(i<=mid){r1[k]=p[i];k++;i++;}
        while(j<=end){r1[k]=p[j];k++;j++;}
        for(int i=str;i<=end;i++){
            p[i]=r1[i];
        } 
    }

    以下是朴素归并排序的瑞士轮CODE:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n,r,q;
    struct node{
        int num,s,w;
    }p[200010],r1[200010];
    
    bool cmp(node x,node y){
        if(x.s==y.s) return x.num<y.num;
        return x.s>y.s;
    }
    
    void msort(int str,int end){//归并:from big to smasll
        if(str==end) return;
        int mid=(str+end)>>1;
        msort(str,mid);
        msort(mid+1,end);
        int i=str,j=mid+1,k=str;
        while(i<=mid&&j<=end){
            if(cmp(p[i],p[j])){
                r1[k].s=p[i].s;
                r1[k].num=p[i].num;
                r1[k].w=p[i].w;
                k++;i++;
            }
            else {
                r1[k].s=p[j].s;
                r1[k].num=p[j].num;
                r1[k].w=p[j].w;
                k++;j++;
            }
        }
        while(i<=mid){r1[k].s=p[i].s;r1[k].num=p[i].num;r1[k].w=p[i].w;k++;i++;}
        while(j<=end){r1[k].s=p[j].s;r1[k].num=p[j].num;r1[k].w=p[j].w;k++;j++;}
        for(int i=str;i<=end;i++){
            p[i].s=r1[i].s;
            p[i].num=r1[i].num;
            p[i].w=r1[i].w;//好像结构体可以整体赋值但这不是咱菜吗qwq
        } 
    }
    
    int main(){
        scanf("%d %d %d",&n,&r,&q);
        for(int i=1;i<=2*n;i++)
          scanf("%d",&p[i].s),p[i].num=i;
        for(int i=1;i<=2*n;i++)
          scanf("%d",&p[i].w);
        sort(p+1,p+2*n+1,cmp);
        for(int i=1;i<=r;i++){
            for(int j=1;j<=2*n;j+=2){
                if(p[j].w>p[j+1].w) p[j].s++;else p[j+1].s++;//进行两两比较
            }
            msort(1,2*n);
        }
        cout<<p[q].num<<endl;
    }

    以下是大概是算了我去测试一下(逃 亲测可以不开o2就ac的思路

    首先进行一遍sort,然后优化在于这里的思路只需要进行一次归并排序:

    将比赛的输赢分别记录在一个数组中,赢的人记录在一起(win),输的人记录在一起(lose),并记录人数。因为一次比赛最多对每个人的成绩更改1,因此整个序列的顺序的波动(尤其当序列很长的时候)不会特别大,这样我们需要排序的数据就少了。对于每次比赛后,我们进行一次优化的归并排序:

    • 两个指针i和j,分别指向的是赢的所有人和输的所有人,当赢的人加上赢得的这一分比分后顺序发生改变,我们就更改这两个数组的顺序,然后将分数较低的继续与下一个比较。直到全部比较完成。
    • 这样归并就省去了排子区间的时间,而是直接对这一个区间进行排序,就不会T掉了;

    以下附链接吧(咱也不能投人家的代码是吧,但是咱也不想写自己的代码

    关于瑞士轮(P1309)以及引申出来的种种问题

    end-

  • 相关阅读:
    JS 基于面向对象的 轮播图1
    JS 原型继承的几种方法
    angularJs 自定义服务 provide 与 factory 的区别
    C# 调用JS Eval,高效率
    Linq表连接大全(INNER JOIN、LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN、CROSS JOIN)
    C# LINQ干掉for循环
    C# 彻底搞懂async/await
    .NET中的异步编程——动机和单元测试
    .NET中的异步编程——常见的错误和最佳实践
    C# 实用代码段
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/11027708.html
Copyright © 2011-2022 走看看