第三讲:田忌赛马

题目: AcWing 1489. 田忌赛马
这是中国历史上的一个著名故事。

大约 2300 年前,田忌是齐国的一位将军,他喜欢与国王等人赛马。

田忌和国王都有三匹不同等级的马----下马、中马、上马。

规则是一场比赛要进行三个回合,每匹马进行一回合的较量,单回合的获胜者可以从失败者那里得到 200 银元。

比赛的时候,国王总是用自己的上马对田忌的上马,中马对中马,下马对下马。

由于国王每个等级的马都比田忌的马强一些,所以比赛了几次,田忌都失败了,每次国王都能从田忌那里拿走 600 银元。

田忌对此深感不满,直到他遇到了著名的军事家孙膑,利用孙膑给他出的主意,田忌终于在与国王的赛马中取得了胜利,拿走了国王的 200 银元。

其实胜利的方法非常简单,他用下马对战国王的上马,上马对战国王的中马,中马对战国王的下马,这样虽然第一回合输了,但是后两回合都胜了,最终两胜一负,取得了比赛胜利。
在这里插入图片描述
如果田忌活在如今,那么他可能会嘲笑自己当初的愚蠢。

重要的是,如果他现在正参加 ACM 竞赛,他可能会发现赛马问题可以简单地看作是在二分图中找到最大匹配项。

在一侧画田忌的马,在另一侧画国王的马,只要田忌的一匹马能够击败国王的一匹马,我们就在这两匹马之间画一条边。

然后,赢尽可能多的回合,就变成了在这个二分图中找到最大匹配。

如果存在平局,问题会变得更加复杂,他需要为所有可能的边分配权重 0、1 或 −1,并找到最大加权的完美匹配…

然而,赛马问题其实是二分图匹配的一种非常特殊的情况。

该图由马的速度决定,速度快的总是能击败速度慢的。

这种情况下,加权二分图匹配算法就显得大材小用了。

在这个问题中,你需要编写一个程序,来解决这一特殊的匹配问题。

输入格式
输入包含最多 50 组测试数据。

每组数据第一行包含一个整数 n,表示一方马的数量。

第二行包含 n 个整数,是田忌的马的速度。

第三行包含 n 个整数,是国王的马的速度。

输入的最后一行为 0,表示输入结束。

输出格式
每组数据输出一个占一行的整数,表示田忌最多可以获得多少银元。

数据范围
1≤n≤1000
马的速度不超过 1000。

输入样例:

3
92 83 71
95 87 74
2
20 20
20 20
2
20 19
22 18
0

输出样例:

200
0
0

题目分析:
这道题是贪心题,先进行排序,然后从小到大
如果田忌的马大于国王的马,那么田忌必赢
如果田忌的马小于国王的马,那么田忌必输,那么就让田忌最小马去对国王最大的马
如果田忌的马等于国王的马,那么我们就看田忌和国王最大的马
如果田忌最大的马大于国王最大的马,那么我们就将田忌和国王最大的马进行比赛
如果田忌最大的马小于国王最大的马,那么我们就让田忌最小的马对国王最大的马
如果田忌最大的马等于国王最大的马,那么我们就让田忌最小的马对国王最大的马,(根据贪心来的,因为这样会得到最优解)
这样一直持续下去,最后就会对完

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;
int n;
int a[N],b[N];

int judge(int x,int y)
{
    if(a[x]>b[y])return 1;
    else if(a[x]<b[y])return -1;
    return 0;
}
int main()
{
    while(cin>>n&&n>0)
    {
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=0;i<n;i++)cin>>b[i];
        
        sort(a,a+n,greater<int>());
        sort(b,b+n,greater<int>());
        
        int f1=0,f2=0,s1=n-1,s2=n-1;
        int res=0;
        while(f1<=s1)
        {
            if(judge(s1,s2)==1)res++,s1--,s2--;
            else if(judge(s1,s2)==-1)res+=judge(s1,f2),s1--,f2++;
            else{
                if(judge(f1,f2)==1)res++,f1++,f2++;
                else res+=judge(s1,f2),s1--,f2++;
            }
        }
        cout<<res*200<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗吧!骚年!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值