POJ - 2287 Tian Ji -- The Horse Racing

题目来源

2287 -- Tian Ji -- The Horse Racing (poj.org)

题目描述

田忌赛马是中国历史上一个著名的故事。

这个故事发生在2300年前,田忌是齐国的一个大官,他喜欢和齐王以及其他公子赛马。

田忌和齐王都有三类马,分别是下等马,中等马,上等马。

比赛一共进行三轮,每匹马只能在某一轮比赛中使用。每一轮的胜者可以从败者获得200银币。

齐王是齐国最有权势的人,因此他的马都非常好,每个级别的马都要比田忌的同级别的马更好。因此,田忌每次都会输600银币给齐王。

田忌为此非常苦恼,直到他遇见了孙膑,这个中国历史上最有名的军师之一。孙膑为田忌提供了如下策略,让田忌在接下来的比赛中赢回了200银币。这是一个非常简单的策略,即:

  • 田忌的下等马 vs 国君的上等马(田忌输,失去200银币)
  • 田忌的中等马 vs 国君的下等马(田忌赢,获得200银币)
  • 田忌的上等马 vs 国君的中等马(田忌赢,获得200银币)

其实上面的赛马问题可以简单地看成是:二分图中寻找最大匹配。

把田忌的马画在一遍,把齐王的马画在另一边。

田忌的马只要能战胜齐王的马,我们就在这两匹马之间画一道连接线,表示我们希望让这两匹马进行匹配比赛。

那么,田忌赢得尽可能多的回合,其实就是在这个图中找到最大匹配。

如果存在平手,那么问题就会变得更佳复杂,他需要为所有可能的变分配权重0、1或-1,并找到一个最大的加权完美匹配。

然后,赛马问题是一个非常特殊的二分图匹配问题。这张图是由马的速度决定的。速度较快的顶点总是胜过速度较慢的顶点。在这种情况下,加权二分图匹配算法显得有点大材小用了。

请你设计一个算法来解决这种特殊匹配问题。

输入描述

最多输入50组用例。

每组用例:

  • 第一行为一个整数n(n ≤ 100)表示每一方马的数量。
  • 第二行为n个整数,表示田忌的马的速度。
  • 第三行为n个整数,表示齐王的马的速度。

输入的结束条件是,在最后一组用例之后输入只有'0'的一行。

输出描述

对每组用例输出一行,每行包含一个整数,表示该组用例下,田忌所能获得最大银币数。

用例

输入3
92 83 71
95 87 74
2
20 20
20 20
2
20 19
22 18
0
输出200
0
0
说明

题目解析

本题可以使用贪心思维去解决问题。

即:要想田忌获得银币最多,则应该让田忌输的最少,那么如何让田忌输的最少呢?

那就是用田忌 "必输的" 且 "最慢的" 马 去消耗掉 齐王最快的马。

因此,我们需要先将田忌和齐王的马进行升序,这样就能找到最慢和最快的马。

  • 如果田忌最快的马 > 齐王最快的马,则此轮田忌胜出
  • 如果田忌最快的马 < 齐王最快的马,则此轮田忌必输,但是为了保留住田忌最快的马,我们应该让田忌把最慢的马拿出来比赛,这样就会以最小代价输。
  • 如果条件最快的马 == 齐王最快的马,则此轮田忌平局,但是代价确实失去了最快的马,此时我们应该考虑从田忌的马中,找到一匹必输的、且最慢的马的去消耗掉齐王的最快的马,这样虽然此轮输了,但是田忌只是将必输的那匹马提前输了而已,好处是,保留住了最快的马。因此接下来我们应该找到田忌必输的,且最慢的马。
  1. 如果田忌最慢的马 > 齐王最慢的马,则当前田忌最慢的马不是田忌必输的、最慢的马,我们应该继续寻找
  2. 如果田忌最慢的马 < 齐王最慢的马,则当前田忌最慢的马就是田忌必输的、且最慢的马,我们应该拿这匹马和齐王最快的马比赛
  3. 如果田忌最慢的马 == 齐王最慢的马,则当前田忌最慢的马不是田忌必输的且最慢的马,我们应该继续寻找

JS算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];

rl.on("line", (line) => {
  if (line == "0") {
    const cases = [];

    for (let i = 0; i < lines.length; i += 3) {
      const n = parseInt(lines[i]);
      const a = lines[i + 1].split(" ").map(Number); // 田忌的马速度数组
      const b = lines[i + 2].split(" ").map(Number); // 齐王的马速度数组
      cases.push([n, a, b]);
    }

    getResult(cases);

    lines.length = 0;
  } else {
    lines.push(line);
  }
});

function getResult(cases) {
  for (let c of cases) {
    const n = c[0];
    const a = c[1];
    const b = c[2];

    a.sort((a, b) => a - b);
    b.sort((a, b) => a - b);

    let la = 0; // 指向田忌最慢的马
    let ra = n - 1; // 指向田忌最快的马

    let lb = 0; // 指向齐王最慢的马
    let rb = n - 1; // 指向齐王最快的马

    let ans = 0; // 记录田忌获得银币数

    while (la <= ra) {
      if (a[ra] > b[rb]) {
        // 田忌最快的马 比 齐王最快的马要快, 则直接比
        ans += 200;
        ra--;
        rb--;
      } else if (a[ra] < b[rb]) {
        // 田忌最快的马 比 齐王最快的马要慢, 则结果肯定输, 为了保留田忌最快的马, 我们应该用田忌最慢的马去消耗掉齐王最快的马
        ans -= 200;
        la++;
        rb--;
      } else {
        // 田忌最快的马 和 齐王最快的 速度相同, 此时如果平局的话,则会让田忌损失最快的马,因此我们应该找到田忌最慢的马, 即田忌必输的马来消耗掉齐王最快的马
        if (a[la] > b[lb]) {
          // 如果田忌最慢的马 比 齐王最慢的马 快, 则此时田忌最慢的马不是必输的马
          ans += 200;
          la++;
          lb++;
        } else {
          // 如果田忌最慢的马速度 <= 齐王最慢的马速度, 此时应该让田忌最慢的马 去消耗  齐王最快的马

          // 如果齐王最快的马速度 > 田忌最慢的马速度,则田忌失去银币
          // 如果齐王最快的马速度 == 田忌最慢的马速度,则田忌不失去银币
          if (b[rb] > a[la]) ans -= 200;
          la++;
          rb--;
        }
      }
    }

    console.log(ans);
  }
}

 

Java算法源码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
  static class Case {
    int n;
    int[] a; // 田忌的马速度数组
    int[] b; // 齐王的马速度数组

    public Case(int n, int[] a, int[] b) {
      this.n = n;
      this.a = a;
      this.b = b;
    }
  }

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    ArrayList<Case> cases = new ArrayList<>();
    // POJ Java只支持jdk1.5, 因此如果需要在POJ验证的话,需要替换为下面更低级的语法
    //    ArrayList cases = new ArrayList();

    while (true) {
      String line = sc.next();

      if ("0".equals(line)) {
        getResult(cases);
        break;
      } else {
        int n = Integer.parseInt(line);
        int[] a = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        int[] b = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();

        // POJ Java只支持jdk1.5, 因此如果需要在POJ验证的话,需要替换为下面更低级的语法
        //        int[] a = new int[n];
        //        for (int i = 0; i < n; i++) a[i] = Integer.parseInt(sc.next());
        //
        //        int[] b = new int[n];
        //        for (int i = 0; i < n; i++) b[i] = Integer.parseInt(sc.next());

        cases.add(new Case(n, a, b));
      }
    }
  }

  public static void getResult(ArrayList<Case> cases) {
    for (Case c : cases) {
      int n = c.n;
      int[] a = c.a;
      int[] b = c.b;

      Arrays.sort(a);
      Arrays.sort(b);

      int la = 0; // 指向田忌最慢的马
      int ra = n - 1; // 指向田忌最快的马

      int lb = 0; // 指向齐王最慢的马
      int rb = n - 1; // 指向齐王最快的马

      int ans = 0; // 记录田忌获得银币数

      while (la <= ra) {
        if (a[ra] > b[rb]) {
          // 田忌最快的马 比 齐王最快的马要快, 则直接比
          ans += 200;
          ra--;
          rb--;
        } else if (a[ra] < b[rb]) {
          // 田忌最快的马 比 齐王最快的马要慢, 则结果肯定输, 为了保留田忌最快的马, 我们应该用田忌最慢的马去消耗掉齐王最快的马
          ans -= 200;
          la++;
          rb--;
        } else {
          // 田忌最快的马 和 齐王最快的 速度相同, 此时如果平局的话,则会让田忌损失最快的马,因此我们应该找到田忌最慢的马, 即田忌必输的马来消耗掉齐王最快的马
          if (a[la] > b[lb]) {
            // 如果田忌最慢的马 比 齐王最慢的马 快, 则此时田忌最慢的马不是必输的马
            ans += 200;
            la++;
            lb++;
          } else {
            // 如果田忌最慢的马速度 <= 齐王最慢的马速度, 此时应该让田忌最慢的马 去消耗  齐王最快的马

            // 如果齐王最快的马速度 > 田忌最慢的马速度,则田忌失去银币
            // 如果齐王最快的马速度 == 田忌最慢的马速度,则田忌不失去银币
            if (b[rb] > a[la]) ans -= 200;
            la++;
            rb--;
          }
        }
      }

      System.out.println(ans);
    }
  }
}

 

Python算法源码

# 算法入口
def getResult(cases):
    for case in cases:
        n = case[0]
        a = case[1]
        b = case[2]

        a.sort()
        b.sort()

        la = 0  # 指向田忌最慢的马
        ra = n - 1  # 指向田忌最快的马

        lb = 0  # 指向齐王最慢的马
        rb = n - 1  # 指向齐王最快的马

        ans = 0  # 记录田忌获得银币数

        while la <= ra:
            if a[ra] > b[rb]:
                #  田忌最快的马 比 齐王最快的马要快, 则直接比
                ans += 200
                ra -= 1
                rb -= 1
            elif a[ra] < b[rb]:
                # 田忌最快的马 比 齐王最快的马要慢, 则结果肯定输, 为了保留田忌最快的马, 我们应该用田忌最慢的马去消耗掉齐王最快的马
                ans -= 200
                la += 1
                rb -= 1
            else:
                # 田忌最快的马 和 齐王最快的 速度相同, 此时如果平局的话,则会让田忌损失最快的马,因此我们应该找到田忌最慢的马, 即田忌必输的马来消耗掉齐王最快的马
                if a[la] > b[lb]:
                    # 如果田忌最慢的马 比 齐王最慢的马 快, 则此时田忌最慢的马不是必输的马
                    ans += 200
                    la += 1
                    lb += 1
                else:
                    # 如果田忌最慢的马速度 <= 齐王最慢的马速度, 此时应该让田忌最慢的马 去消耗  齐王最快的马
                    # 如果齐王最快的马速度 > 田忌最慢的马速度,则田忌失去银币
                    # 如果齐王最快的马速度 == 田忌最慢的马速度,则田忌不失去银币
                    if b[rb] > a[la]:
                        ans -= 200
                    la += 1
                    rb -= 1

        print(ans)


# 输入获取
cases = []

while True:
    line = input()

    if line == "0":
        # 算法调用
        getResult(cases)
        break
    else:
        n = int(line)
        a = list(map(int, input().split()))  # 田忌的马速度数组
        b = list(map(int, input().split()))  # 齐王的马速度数组
        cases.append([n, a, b])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/31491.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Vue】学习笔记-创建Vue3.0工程

创建Vue3.0工程 使用vue-cli创建查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上安装或者升级你的vue/cli创建启动 使用vite创建创建工程进入工程目录安装依赖运行 使用vue-cli创建 官方文档&#xff1a;https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-…

BioXFinder生物数据库

BioXFinder是目前国内第一个也是国内唯一一个生物信息数据库&#xff0c;由享融智云公司精心研发&#xff0c;主要针对生物科研工作者的综合性生物数据检索及分析平台&#xff0c;汇集了核酸、蛋白、蛋白结构、代谢通路和信号通路信息&#xff0c;解决海外数据访问难、访问慢的…

【新星计划·2023】Linux是什么?它与Windows有什么区别?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、Linux是什么&#xff1f; 二、Linux的应用领域 1、服务器领域 2、嵌入式领域 3、虚拟化 三、Linux的未来 1、云计算 2、大数…

玩转ChatGPT:回答审稿人问题

一、写在前面 前段时间一篇时间序列预测的文章返修&#xff0c;还挺幸运的&#xff0c;给了个小修。 不过问题也问得有点刁钻&#xff0c;应该是个行家。 想到手头有小Chat&#xff0c;打算使用TA来辅助我回答审稿人问题。 以下展示仅仅提供一个工作流和思路&#xff0c;具体…

高级SQL语句

目录 MySQL 高级(进阶) SQL 语句函数数学函数&#xff1a;聚合函数字符串函数&#xff1a; 连接查询inner join(内连接)&#xff1a;left join(左连接)&#xff1a;right join(右连接)&#xff1a; CREATE VIEW&#xff08;视图&#xff09;UNION&#xff08;联集&#xff09;C…

OpenAI ChatGPT 使用示例(程序员)

作为一个程序员&#xff0c;当知道ChatGPT出来之后或者GPT3出来的时候&#xff0c;我是有喜有忧&#xff0c;喜的是它可以帮我写代码&#xff0c;重构代码&#xff0c;写注释&#xff0c;写测试&#xff0c;&#xff0c;。哇&#xff0c;听起来好刺激&#xff0c;我可以从此以后…

探索安卓内容提供者:构建、访问和管理数据【复习】

文章目录 一 ContentProvider1.1 数据模型- **ContentProvider 使用基于数据库模型的简单表格来提供需要共享的数据**&#xff0c;在该表格中&#xff0c;每一表示一条记录&#xff0c;而每一列代表特定类型和含义的数据&#xff0c;并且其中每一条数据记录都包含一个名为“_ID…

数字图像处理 基于matlab、opencv计算图像的梯度方向和梯度幅值

一、图像的梯度 1、简述 图像可以被视为标量场(即二维函数)。 通过微分将标量场转换为矢量场。 梯度是一个向量,描述了在x或y方向上移动时,图像变化的速度。我们使用导数来回答这样的问题,图像梯度的大小告诉图像变化的速度,而梯度的方向告诉图像变化最…

【C++学习】C++入门 | 引用 | 引用的底层原理 | auto关键字 | 范围for(语法糖)

写在前面&#xff1a; 上一篇文章我介绍了缺省参数和函数重载&#xff0c; 探究了C为什么能够支持函数重载而C语言不能&#xff0c; 这里是传送门&#xff0c;有兴趣可以去看看&#xff1a;http://t.csdn.cn/29ycJ 这篇我们继续来学习C的基础知识。 目录 写在前面&#x…

图像金字塔

​ 图像金字塔是由一幅图像的多个不同分辨率的子图构成的图像集合。是通过一个图像不断的降低采样率产生的&#xff0c;最小的图像可能仅仅有一个像素点。下图是一个图像金子塔的示例。从图中可以看到&#xff0c;图像金字塔是一系列以金字塔形状排列的、自底向上分辨率逐渐降低…

【数字图像处理】3.对比度增强

目录 3.1 灰度直方图 3.2 线性变换 3.3 直方图正规化 3.4 伽马变换 3.5 全局直方图均衡化 3.6 CLAHE 对比度增强是图像增强的一种&#xff0c;它主要解决的是图像的灰度级范围较小造成的对比度较低的问题&#xff0c;目的是将图像的灰度级增强到指定范围&#xff0c;使得…

实战:用docker-compose容器化springboot项目

文章目录 前言技术积累docker-compose定义docker-compose文件参数docker-compose命令 实战演示1、创建挂载路径2、编写docker-compose.yml3、启动并管理容器 写在最后 前言 前面我们学习和实战了用dockerfile构建镜像&#xff0c;通过镜像可以任意在docker环境容器化部署项目。…

Opencv-C++笔记 (7) : opencv-文件操作XML和YMAL文件

文章目录 一、概述二、文件操作三、打开文件四、写入五、读写个人源码 一、概述 除了图像数据之外&#xff0c;有时程序中的尺寸较小的Mat类矩阵、字符串、数组等 数据也需要进行保存&#xff0c;这些数据通常保存成XML文件或者YAML文件。本小节中将介绍如何利用OpenCV 4中的函…

神经网络:卷积操作

当谈到计算机视觉中的网络模型结构时&#xff0c;卷积操作是其中一个关键的组成部分。卷积操作是一种基于局部区域的操作&#xff0c;它在计算机视觉中用于图像处理和特征提取。 卷积操作的原理如下&#xff1a; 给定一个输入图像和一个称为卷积核&#xff08;或滤波器&#x…

【ARIMA-SSA-LSTM】合差分自回归移动平均方法-麻雀优化-长短期记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

前端Vue自定义数字输入框 带加减按钮的数字输入框组件

前端Vue自定义数字输入框 带加减按钮的数字输入框组件&#xff0c; 下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13163 效果图如下&#xff1a; # cc-numbox #### 使用方法 使用方法 <!-- title: 标题 isSetMax: 是否设置最…

synchronized原理

Synchronized能够实现原子性和可见性&#xff1a;在Java内存模型中&#xff0c;synchronized规定&#xff0c;线程在加锁时&#xff0c;先清空工作内存→在主内存中拷贝最新变量的副本到工作内存→执行完代码→将更改后的共享变量的值刷新到主内存中→释放互斥锁。 synchroniz…

Axure教程—折叠面手风琴效果

上文中介绍了用Axure制作折叠面板的基础制作&#xff0c;这次介绍折叠面板手机风琴效果 效果 预览地址&#xff1a;https://e18rf6.axshare.com 功能 点击标题展开内容&#xff0c;点击另一标题&#xff0c;其展开的内容折叠 制作 拖入四个动态面板&#xff0c;分别命名为1、…

【微服务】springboot 通用限流方案设计与实现

目录 一、背景 二、限流概述 2.1 dubbo 服务治理模式 2.1.1 dubbo框架级限流 2.1.2 线程池设置 2.1.3 集成第三方组件 2.2 springcloud 服务治理模式 2.2.1 hystrix 2.2.2 sentinel 2.3 网关层限流 三、常用限流策略 3.1 限流常用的算法 3.1.1 令牌桶算法 3.1.2 …

【深度学习】2-5 神经网络-批处理

批处理&#xff08;Batch Processing&#xff09;是指在深度学习中每次迭代更新模型参数时同时处理多个样本的方式。 批处理时要注意对应维度的元素个数要一致 关于之前手写数字识别的例子&#xff1a; 用图表示&#xff0c;可以发现&#xff0c;多维数组的对应维度的元素个数…