中南林业大学11th F 新田忌赛马 优先队列

本文介绍了一种基于贪心算法的田忌赛马问题解决方案,通过非递减排序及优先队列策略,实现了马匹对阵的最佳配置,最大化赢得刀币数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述 

田忌和齐威王又开始赛马了,这一次齐威王为了增加难度,在每一匹马上都设置了一个刀币值,如果田忌赢了这匹马,那么他就可以获得相应的刀币,否则他就要失去相应的刀币(平局田忌也要失去刀币)。现在齐威王和田忌各有n匹马,每匹马有一个速度值,齐威王的每匹马还有一个刀币值,速度快的马会获得胜利,速度相同则是平局。现在齐威王已经排好了马的顺序,请你帮助田忌排兵布阵,并计算出他最多可以赢得多少刀币?(如果最后是输钱就请输出负数)。

例如:当有n=3匹马的时候

齐威王三匹马的速度为40, 30, 20

三匹马对应的刀币值为 1,2,3

田忌三匹马的速度为  20,30,50

齐威王的马顺序固定,田忌可以随意调动马匹出场顺序

当田忌出场顺序为   20,50,30 的时候

田忌会先失去一个刀币,再获得两个刀币,再获得三个刀币,故最后田忌赢得四个刀币,输出4,如果输了x个刀币就输出x的负数。

输入描述:

输入第一行包含一个整数T,代表测试案例个数。(5<=T<=10)

接下来每个测试案例都包括四行

第一行为一个整数n(0<n<=1000),代表马的个数。

第二行为n个整数,代表齐威王各匹马的速度。

第三行为n个整数,代表齐威王各匹马的刀币值(0<刀币值<=100),与速度值一一对应。

第四行为n个整数,代表田忌各匹马的速度。(0<速度值<=100)

输出描述:

输出田忌最多可以赢得的刀币值。
示例1

输入

2
3
40 30 20
1 2 3
20 30 50
5
25 25 50 60 10
10 50 5 100 30
70 5 30 25 40

输出

4
185

题解 :

贪心

首先田忌和齐威王的马的速度非递减排序

对于田忌的马 i 来说 将齐威王所有速度小于马i的马放进优先队列.

从中选择分值最大的.

这样对于 田忌的马 i + 1 来说,还在优先队列中的小于马i速度的马也满足小于马i+1

于是最后弹出来的都是田忌的马能战胜的,且其获得的分值也是最多的.

最后队列里剩下的还有剩下没放进队列的都是田忌输掉的马.最后减去即可.


这样的算法复杂度是O(n+m)

而这题n的大小O(n^2)也能解决


这样的问题已经很多次了

传送门

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3+10;
struct House{
    ll speed,val;
    bool operator < (const House &a) const {
        return speed < a.speed;
    }
};
House wang[maxn];
ll tian[maxn];
priority_queue<int,vector<int>,less<int> > qu;
int main()
{
    int caset;scanf("%d",&caset);
    while(caset--) 
    {
        while(!qu.empty()) qu.pop();
        int n;scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%lld",&wang[i].speed);
        for(int i=0;i<n;i++) scanf("%lld",&wang[i].val);
        for(int i=0;i<n;i++) scanf("%lld",&tian[i]);
        sort(wang,wang+n);sort(tian,tian+n);
        ll ans = 0;
        int pos = 0;
        for(int i=0;i<n;i++) {
            while(pos < n && wang[pos].speed < tian[i]) qu.push(wang[pos++].val);
            if(qu.empty()) continue;
            ans += qu.top();
            qu.pop();
        }
        /// 2333 忘了还有没有遍历完的
        while(pos < n) qu.push(wang[pos++].val);
        while(!qu.empty()) ans -= qu.top(),qu.pop();
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值