【洛谷P1309】瑞士轮

P1309瑞士轮

本题同样是NOIP普及组第三题。
因为太久没有做过题目了,先从普及组开始练习吧。
题目内容

思路1

很显然想到的思路就是模拟,代码如下:

#include 
#include 
#include 
#include 
using namespace std;

struct Player{
    int id;
    int score;
    int weight;
    bool operator< (const Player& player)
    {
        return this->weight<player.weight;
    }
};

bool cmp(Player a,Player b)
{
    if(a.score!=b.score)
    {
        return a.score>b.score;
    }
    else
    {
        return a.id<b.id;
    }
}

int main(void)
{
    int n,r,q;
    cin>>n>>r>>q;
    vector<Player> player(2*n);
    for(int i = 0;i<2*n;i++)
    {
        player[i].id=i+1;
        cin>>player[i].score;
    }
    for(int i = 0;i<2*n;i++)
    {
        cin>>player[i].weight;
    }
    sort(player.begin(),player.end(),cmp);//按初始成绩排序

    for(int i=0;i<r;i++)//r轮比赛
    {
        for(int j=0;j<n;j++)
        {
            if(player[2*j].weight>player[2*j+1].weight)
            {
                player[2*j].score+=1;
            }
            else
            {
                player[2*j+1].score+=1;
            }
        }
        sort(player.begin(),player.end(),cmp);

    }
    cout<<player[q-1].id<<endl;
    return 0;
}

只有60分,有4个点超时了。
分析一下算法,因为要对R轮比赛的N次比较都进行计算,再进行一次快排,所以时间复杂度大约为O(r(n+nlogn))这个量级。其中N最大可以取到 1 0 5 10^5 105,R=50,单纯计算不会超过 5 × 1 0 8 5\times 10^8 5×108,接近 1 0 9 10^9 109,在常数稍微大一点的时候确实有超时的可能。

思路2

显然可以发现,快排是毫无必要的,因为分数的变动最多只会导致邻近顺位的变化。
题解中有个思路很好,两者相比,胜者入队A,负者入队B,再将AB两队归并。显然,归并的时间复杂度为O(n),略微优于快排的O(nlogn)

#include 
#include 
#include 
#include 
using namespace std;

struct Player{
    int id;
    int score;
    int weight;
    bool operator< (const Player& player) const
    {
        if(this->score!=player.score)
        {
            return this->score<player.score;
        }
        else
        {
            return this->id>player.id;
        }
    }
    bool operator> (const Player& player) const
    {
        if(this->score!=player.score)
        {
            return this->score>player.score;
        }
        else
        {
            return this->id<player.id;
        }
    }
    Player& operator=(const Player& player)
    {
        this->id = player.id;
        this->score = player.score;
        this->weight = player.weight;
        return *this;
    }
};

bool cmp(Player a,Player b)
{
    if(a.score!=b.score)
    {
        return a.score>b.score;
    }
    else
    {
        return a.id<b.id;
    }
}

int main(void)
{
    int n,r,q;
    cin>>n>>r>>q;
    vector<Player> player(2*n);
    for(int i = 0;i<2*n;i++)
    {
        player[i].id=i+1;
        cin>>player[i].score;
    }
    for(int i = 0;i<2*n;i++)
    {
        cin>>player[i].weight;
    }
    sort(player.begin(),player.end(),cmp);//按初始成绩排序

    for(int i=0;i<r;i++)//r轮比赛
    {
        vector<Player> win,lose;
        for(int j=0;j<n;j++)
        {
            if(player[2*j].weight>player[2*j+1].weight)
            {
                player[2*j].score+=1;
                win.push_back(player[2*j]);
                lose.push_back(player[2*j+1]);
            }
            else
            {
                player[2*j+1].score+=1;
                win.push_back(player[2*j+1]);
                lose.push_back(player[2*j]);
            }
        }
        //归并
        int k=0,k1=0,k2=0;
        while(k1<n&&k2<n)
        {
            if(win[k1]>lose[k2])
            {
                player[k]=win[k1];
                k++,k1++;
            }
            else
            {
                player[k]=lose[k2];
                k++,k2++;
            }
        }
        while(k1<n)
        {
            player[k]=win[k1];
            k++,k1++;
        }
        while(k2<n)
        {
            player[k]=lose[k2];
            k++,k2++;
        }
    }
    cout<<player[q-1].id<<endl;
    return 0;
}

你可能感兴趣的:(OJ,算法题解)