1489. 田忌赛马(贪心)

2023-11-12

这是中国历史上的一个著名故事。

大约 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

思路分析

在这里插入图片描述
      假设田忌最快的马为f1,最慢的马为s1,国王最快的马为f2,最慢的马为s2。因为我们想让田忌赢尽可能多的比赛(温馨提示:VS代表让两人对应编号的马进行比赛)。
则有以下情况:

  1. s1>s2时,让s1 VS s2,此时田忌会赢一场。
  2. s1<s2时,让s1 VS f2,因为田忌的马s1 是最慢的马,它比国王最慢的马s2还慢,所以田忌的这匹马,无论与国王的哪匹马相比都是输的。此时可以让田忌最垃圾的马去打国王最厉害的马,即让这匹马当炮灰去把国王的马的整体速度给拉下来,这样能让田忌在接下来的比赛中能有更大的机会去赢。
  3. s1=s2时,田忌最慢的马和国王最慢的马速度相等,即此时田忌的马要么是输,要么是平局,因为输的话可以拿它去当炮灰把国王的马的整体速度给拉下来,这样能让田忌在接下来的比赛中能有更大的机会去赢。所以此时无法确定哪种选择是更优的。因此在此条件下再来比较最快的马看看(思考一下:为什么要比较最快的马呢?因为想在国王必赢的极端条件下用最慢的马来当炮灰)。
           3.1 f1>f2时,让f1 VS f2,因为田忌最快的马f1 比国王最快的马f2都快,所以田忌这匹马是必赢的,让它去打国王最快的马,这既能赢一场比赛,又把国王的马的速度给拉下来 。
           3.2 f1<f2时,让s1 VS f2,因为田忌最快的马f1 比国王最快的马f2都慢,所以国王这匹马是必赢的,此时只能让田忌最慢的马s1去当炮灰,去把国王的马的速度给拉下来 。
           3.3 f1=f2时,让s1 VS f2,因为此时 s1=s2且 f1=f2。s1有两种选择
           ① s1 VS s2。(平局)
           ② s1 VS f2(因为有可能s1 = f2,所以田忌有可能输一场)。
           假设情况① s1 VS s2。(平局)能取得最优解。
    在这里插入图片描述
    因为 s1 VS s2了,所以f2可以选择田忌的马中的任何一匹马进行比赛设其为x(其中x不包括 s1),此时田忌的马有如下的速度关系, f1>=x>=s1
           假设f1>x。此时田忌净输一场( s1 VS s2,平局, x VS f2,因为f2=f1>x,所以田忌输)。
           我们来看看这种条件下的第二种情况,② s1 VS f2情况会如何。
    在这里插入图片描述
           此时田忌最坏情况下净输一场( s1 VS f2,田忌输, x VS s2,因为x>=s1=s2,当x=s2时平局(田忌净输一场),当x>s2时,田忌赢(两局来看田忌不赢不输))。即情况② s1 VS f2,在最坏的情况下,也不会比情况①差,且情况②有可能比它更好。
           假设f1=x。此时又有两种情况。
    在这里插入图片描述
           当x=s1时,此时有 f1=f2=x=s1=s2。所以情况① s1 VS s2( s1 VS s2平局,x VS f2平局)和② s1 VS f2( s1 VS f2平局,x VS s2平局)两者等价,即两局都是平局。
           当x>s1时,此时有 f1=f2=x>s1=s2。所以情况① s1 VS s2( s1 VS s2平局,x VS f2平局)和② s1 VS f2( s1 VS f2田忌输,x VS s2田忌赢)即从两局总和来看也是平局。
           所以综上所述,情况② s1 VS f2在最坏的情况下也不会比情况① s1 VS s2差,即情况②一定有最优解。注意:这里不是说情况①没有最优解,只是情况①不一定有最优解。但情况②一定有最优解。即3.3 f1=f2时,让s1 VS f2能取得最优解。
    在这里插入图片描述
    在这里插入图片描述
          注意点:是不是还会有小伙伴说我还没思考x<s1的情况。因为x>=s1所以不用考虑。

代码

#include <iostream>
#include<algorithm>
using namespace std;
int a[1005],b[1005];//a数组存储田忌的马的速度,b数组存储国王的马的速度
//判断某场比赛谁赢
int judge(int x,int y){
    if(a[x]>b[y])
        return 1;//田忌赢
    if(a[x]<b[y])
        return -1;//田忌输
    return 0;//平局
}

int main()
{
    int n;
    while(cin>>n,n){//输入多组数据
        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(a[s1]>b[s2]){//s1>s2时,让s1 VS s2
                res++;//田忌赢
                s1--;
                s2--;
            }else if(a[s1]<b[s2]){//s1<s2时,让s1 VS f2
                res--;//田忌输
                s1--;
                f2++;
            }else{//s1=s2时,比较最快的马的情况
                if(a[f1]>b[f2]){// f1>f2时,让f1 VS f2
                    res++;//田忌赢
                    f1++;
                    f2++;
                }else{//f1<f2时和f1=f2时都是让s1 VS f2
                    res+=judge(s1,f2);//这两种情况田忌有输有平,要根据情况决定
                    s1--;
                    f2++;
                }
            }
        }
        cout<<res*200<<endl;//田忌最多可以获得多少银元,注意点一定要乘200
    }
    return 0;
}

写稿不易,如果对您有帮助请帮忙点个赞呗。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

1489. 田忌赛马(贪心) 的相关文章

  • 当我在组合框中选择一个项目时,如何防止 TextChanged 事件?

    我有一个TextChanged http msdn microsoft com en us library system windows forms control textchanged aspx我的事件ComboBox http msd
  • 如何从 C# 中的 dataTable.Select( ) 查询中删除单引号?

    所以我有一个经销商名称列表 我正在我的数据表中搜索它们 问题是 一些傻瓜必须被命名为 Young s 这会导致错误 drs dtDealers Select DealerName dealerName 所以我尝试替换字符串 尽管它对我不起作
  • 计算 XML 中特定 XML 节点的数量

    请参阅此 XML
  • 适合初学者的良好调试器教程[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有谁知道一个好的初学者教程 在 C 中使用调试器 我感觉自己好像错过了很多 我知道怎么做 单步执行代码并查看局部变量 虽然这常常给我带来问
  • 使用 C# 登录《我的世界》

    我正在尝试为自己和一些朋友创建一个简单的自定义 Minecraft 启动器 我不需要启动 Minecraft 的代码 只需要登录的实际代码行 例如 据我所知 您过去可以使用 string netResponse httpGET https
  • 为什么pow函数比简单运算慢?

    从我的一个朋友那里 我听说 pow 函数比简单地将底数乘以它的指数的等价函数要慢 例如 据他介绍 include
  • C++ 是否可以在 MacOS 上与 OpenMP 和 boost 兼容?

    我现在已经尝试了很多事情并得出了一些结论 也许 我监督了一些事情 但似乎我无法完成我想要的事情 问题是 是否有可能使用 OpenMP 和 boost 在 MacOS High Sierra 上编译 C 一些发现 如果我错了请纠正我 Open
  • 查找进程的完整路径

    我已经编写了 C 控制台应用程序 当我启动应用程序时 不使用cmd 我可以看到它列在任务管理器的进程列表中 现在我需要编写另一个应用程序 在其中我需要查找以前的应用程序是否正在运行 我知道应用程序名称和路径 所以我已将管理对象搜索器查询写入
  • 从同一个类中的另一个构造函数调用构造函数

    我有一个带有两个构造函数的类 C 这是代码片段 public class FooBar public FooBar string s constructor 1 some functionality public FooBar int i
  • C# 存档中的文件列表

    我正在创建一个 FileFinder 类 您可以在其中进行如下搜索 var fileFinder new FileFinder new string C MyFolder1 C MyFolder2 new string
  • 类型约束

    我有以下类层次结构 class Header IEnumerable
  • 启动时的 Excel 加载项

    我正在使用 Visual C 创建 Microsoft Excel 的加载项 当我第一次创建解决方案时 它包含一个名为 ThisAddIn Startup 的函数 我在这个函数中添加了以下代码 private void ThisAddIn
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • Unity:通过拦截将两个接口注册为一个单例

    我有一个实现两个接口的类 我想对该类的方法应用拦截 我正在遵循中的建议Unity 将两个接口注册为一个单例 https stackoverflow com questions 1394650 unity register two inter
  • 实体框架中的“it”是什么

    如果以前有人问过这个问题 请原谅我 但我的任何搜索中都没有出现 它 我有两个数据库表 Person 和 Employee 对每个类型的表进行建模 例如 Employee is a Person 在我的 edmx 设计器中 我定义了一个实体
  • 可访问性不一致:参数类型的可访问性低于方法

    我试图在两个表单之间传递一个对象 基本上是对当前登录用户的引用 目前 我在登录表单中有一些类似的内容 private ACTInterface oActInterface public void button1 Click object s
  • 如何在richtextbox中使用多颜色[重复]

    这个问题在这里已经有答案了 我使用 C windows 窗体 并且有 richtextbox 我想将一些文本设置为红色 一些设置为绿色 一些设置为黑色 怎么办呢 附图片 System Windows Forms RichTextBox有一个
  • 灵气序列解析问题

    我在使用 Spirit Qi 2 4 编写解析器时遇到一些问题 我有一系列键值对以以下格式解析
  • 如何使用 C++11 using 语法键入定义函数指针?

    我想写这个 typedef void FunctionPtr using using 我该怎么做呢 它具有类似的语法 只不过您从指针中删除了标识符 using FunctionPtr void 这是一个Example http ideone
  • 如何将十六进制字符串转换为无符号长整型?

    我有以下十六进制值 CString str str T FFF000 如何将其转换为unsigned long 您可以使用strtol作用于常规 C 字符串的函数 它使用指定的基数将字符串转换为 long long l strtol str

随机推荐

  • JavaScript基础--内置对象之Math对象

    Math 对象不是构造函数 不需要new 它具有数学常数和函数的属性和方法 跟数学相关的运算 求绝对值 取整 最大值等 可以使用 Math 中的成员 1 Math对象常用方法 1 1 Max floor Max floor floor表示地
  • sql的基本操作详解

    一 什么是视图 视图 view 是一种虚拟存在的表 是一个逻辑表 本身并不包含数据 作为一个select语句保存在数据字典中的 二 为什么要用视图 视图隐藏了底层的表结构 简化了数据访问操作 客户端不再需要底层表的机构及其之间的关系 视图是
  • UE4 C++获取StaticMesh详细信息

    h UFUNCTION BlueprintCallable Category FunTool void GetStaticMeshDetails UStaticMesh Staticmesh TMap
  • 做期货的时候想到自己挣的钱都是别人亏的钱吗?

    1 换股法 当觉得自己的理财产品实在是没有什么时机了 就选一只与该理财产品价格差不多的 有时机上涨的理财产品来换 也便是等价 或根本等价 换入有上涨期望的理财产品 让后边买入的理财产品上涨后的赢利来抵消前面买入的理财产品因跌落而发生的亏本
  • Spring事务配置文件方式

  • BOOST 库中filesyatem 库的学习

    FileSyatem 库的学习 库的使用方式 嵌入源码的形式 define BOOST SYSTEN NO LIB define BOOST FILESYSTEM NO LIB include
  • 配置文件(properties类)

    基本介绍 1 专门用于读写配置文件的集合类 配置文件格式 键 值 2 注意 键值对 不需要空格 值 不需要用引号 默认类型 String 3 Properties的常见方法 1 load 加载配置文件的键值对到Properties对象 2
  • Win11怎么设置电脑开机密码和锁屏密码

    相信很多用户都已经用上了微软公司为大家提供的全新Win11系统了 Win11与Win10系统有很大区别 不仅仅体现在界面设计和UI上面 狠多以前Win10用户固定的功能有些取消了 有些挪位置了 这让用惯了Win10系统的用户非常不习惯 下面
  • Lua和C++交互详细总结

    转自 http cn cocos2d x org tutorial show id 1474 一 Lua堆栈 要理解Lua和C 交互 首先要理解Lua堆栈 简单来说 Lua和C C 语言通信的主要方法是一个无处不在的虚拟栈 栈的特点是先进后
  • Scrum猪和鸡的故事

    本文转载至 http blog csdn net fen0707 article details 8979942 一天 一头猪和一只鸡在路上散步 鸡看了一下猪说 嗨 我们合伙开一家餐馆怎么样 猪回头看了一下鸡说 好主意 那你准备给餐馆卖什么
  • Java Error org.apache.thrift.transport.TTransportException

    org apache thrift transport TTransportException java net ConnectException Connection refused connect org apache thrift t
  • 利用Python绘制中国新型冠状病毒疫情图(国家和省)

    大数据课程设计上来就要求绘制一个地图可以反应出来中国各个省份每日疫情的人数 包括确诊 疑似 死亡 治愈 如下图所示 这里用到了Python中的pyecharts库 点此了解详细信息 1 先来将需要的模块导入进来 import request
  • Windows 系统上如何安装 Python 环境(详细教程)

    一 下载 64位下载链接 https www python org ftp python 3 7 9 python 3 7 9 amd64 exe 32位下载链接 https www python org ftp python 3 7 9
  • QCheckBox复选框状态设置、信号绑定

    一 QCheckBox有两种设置状态 1 setCheckState Qt Checked 设置状态并且发送信号出去 eg for auto itr m mCheckBoxNum begin itr m mCheckBox end itr
  • (Java)leetcode-814 Binary Tree Pruning(二叉树剪枝)

    题目描述 给定二叉树根结点 root 此外树的每个结点的值要么是 0 要么是 1 返回移除了所有不包含 1 的子树的原二叉树 节点 X 的子树为 X 本身 以及所有 X 的后代 示例1 输入 1 null 0 0 1 输出 1 null 0
  • JDBC工作原理

    JDBC程序描述为包含如下过程的应用 1 引入一个必要的类2 加载JDBC驱动程序3 标识数据源 URL Username Password 4 分配一个Connection对象5 分配一个Statement对象6 使用该Statement
  • 阿里云部署Stable Diffusion

    系列文章目录 本地部署Stable Diffusion教程 亲测可以安装成功 Stable Diffusion界面参数及模型使用 谷歌Colab云端部署Stable Diffusion 进行绘图 文章目录 系列文章目录 前言 一 AIGC是
  • 外挂原理

    一 前言 所谓游戏外挂 其实是一种游戏外辅程序 它可以协助玩家自动产生游戏动作 修 改游戏网络数据包以及修改游 戏内存数据等 以实现玩家用最少的时间和金钱去完成功力升级和过关斩将 虽然 现 在对游戏外挂程序的 合法 身份众说纷纭 在这里我不
  • 数据结构——二叉树 增加、删除、查询

    二叉树系统 public class BinarySystem public static void main String args BinaryDomain root null 定义头结点 new BinaryAction manage
  • 1489. 田忌赛马(贪心)

    这是中国历史上的一个著名故事 大约 2300 年前 田忌是齐国的一位将军 他喜欢与国王等人赛马 田忌和国王都有三匹不同等级的马 下马 中马 上马 规则是一场比赛要进行三个回合 每匹马进行一回合的较量 单回合的获胜者可以从失败者那里得到 20