洛谷 P1489 猫狗大战【背包+bool类型dp】

这篇具有很好参考价值的文章主要介绍了洛谷 P1489 猫狗大战【背包+bool类型dp】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原题链接:https://www.luogu.com.cn/problem/P1489

题目描述

新一年度的猫狗大战通过 SC(星际争霸)这款经典的游戏来较量,野猫和飞狗这对冤家为此已经准备好久了,为了使战争更有难度和戏剧性,双方约定只能选择 Terran(人族)并且只能造机枪兵。

比赛开始了,很快,野猫已经攒足几队机枪兵,试探性的发动进攻;然而,飞狗的机枪兵个数也已经不少了。野猫和飞狗的兵在飞狗的家门口相遇了,于是,便有一场腥风血雨和阵阵惨叫声。由于是在飞狗的家门口,飞狗的兵补给会很快,野猫看敌不过,决定撤退。这时飞狗的兵力也不足够多,所以没追出来。

由于不允许造医生,机枪兵没办法补血。受伤的兵只好忍了。

现在,野猫又攒足了足够的兵力,决定发起第二次进攻。为了使这次进攻给狗狗造成更大的打击,野猫决定把现有的兵分成两部分,从两路进攻。由于有些兵在第一次战斗中受伤了,为了使两部分的兵实力平均些,分的规则是这样的:

  1. 两部分兵的个数最多只能差一个;
  2. 每部分兵的血值总和必须要尽可能接近。

现在请你编写一个程序,给定野猫现在有的兵的个数以及每个兵的血格值,求出野猫按上述规则分成两部分后每部分兵的血值总和。

输入格式

第一行为一个整数 n (1≤n≤200),表示野猫现在有的机枪兵的个数。以下的 n 行每行一个整数,表示每个机枪兵的血格 (1≤ai​≤40)。

输出格式

一行,为两个整数,表示分成两部分后每部分兵的血值总和。要求输出的第一部分兵的血量总和不大于第二部分兵的血量总和。

输入输出样例

输入 #1

3
35
20
32

输出 #1

35 52

说明/提示

TO 狗狗:这道题的数据范围我已经尽量按星际的游戏规则来了,如果你再固执于由于机枪兵的攻击力一定使不能达到某些血格值或者游戏中一定要造农民不能使机枪兵的人数达到 200 的话,我只能决定将那场猫狗大战的录像公开于世人了!!!

解题思路:

首先题目说了俩部分的兵的个数最多只能差1。

当兵的个数为偶数时,分为俩部分俩部分的兵要么相等要么至少相差2(并且俩部分的兵数相差只会是偶数),所以俩部分兵个数相差不能为1,只能相等。

当兵的个数为奇数时,俩部分的兵不可能相等,至少相差1(并且相差兵的个数一定是奇数),所以俩部分兵的个数在这个题目只能相差1。

综上所述我们可以得出一个结论

(1)当兵的个数是偶数时,俩部分的兵的个数只能相等

(2)当兵的个数是奇数时,俩部分的兵的个数只能相差1

初始时兵的数量为n,当n为偶数时,一部分兵的数量为n/2,另一部分兵的数量也为n/2

当n为奇数时,一部分兵的数量为n/2,另一部分兵的数量为n/2+1。

从上述分析可以知道这俩部分必定有一部分兵的数量为n/2,我们令m=n/2,然后我们可以用sum来记录所有的n个兵的总的血量,我们只要知道其中一部分的血量blood,那么另一部分的血量就可以通过sum-blood算出来,所以我们只需要处理其中一部分的血量即可。

由于不管考虑那部分,另一部分都是对称的,所以我们只需要考虑其中一部分即可,这里我们可以考虑兵的个数为m=n/2这一部分兵的血量。

到这里我们已经满足了第一个条件俩部分兵的个数最多相差1,接下需要考虑的就是怎么让俩部分的血量最接近,最简单的办法我们可以枚举m=n/2这一部分,也就是从n个物品中选择m个物品血量可以为哪些值,看到这句话我们就可以看出来这不就是背包问题了吗,下面使用背包进行处理。

状态定义:

定义:f[i][j][k]表示从前i个物品中选,并且刚好选择了j个物品,并且血量刚好为k的选法是否存在。

初始化:

f[0][0][0]=true,  从前0个物品中选只能选择0个物品,并且血量只能为0

状态转移

不选择第i个物品

f[i][j][k] = f[i][j][k] || f[i - 1][j][k];

选择第i个物品

f[i][j][k] = f[i][j][k] || f[i - 1][j - 1][k - a[i]];

最终答案

枚举所有的f[n][m][k] (0<=k<=m*40),看从前n个物品中选择m个物品并且血量刚好为k的情况是否存在,如果存在,那么其中一部分血量为k,另外一部分的血量为sum-k,对所有存在的情况取一个最接近的值即可。

时间复杂度:首先第一维枚举所有物品时间为O(n),第二维枚举选的物品数时间为O(m),第三位枚举血量时间为O(m*40),n=200,m=100,所以时间为200*100*100*40=8e7,这个时间复杂度是有点高,但是常数非常小,是可以过的。

空间复杂度:这个题目看起来空间要搞比较高,再来分析一下空间复杂度,空间为n*m*m*40,大概需要80M,这个题目给了128M,所以空间复杂度是足够的。

cpp代码如下文章来源地址https://www.toymoban.com/news/detail-808207.html

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 210, M = 4010;

int n, m;
int a[N];
bool f[N][110][M];
int main()
{
    cin >> n;
    int sum = 0;  //sum记录所有兵的总血量
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]), sum += a[i];

    m = n / 2;  //其中一部分的兵的个数
    f[0][0][0] = true;  //初始化
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= i && j <= m; j++)  //最多只能选择m个物品,
            for (int k = 0; k <= j * 40; k++)   
            {
                //不选择当前物品
                f[i][j][k] = f[i][j][k] || f[i - 1][j][k];
                //选择当前物品
                if (k >= a[i] && j >= 1)
                    f[i][j][k] = f[i][j][k] || f[i - 1][j - 1][k - a[i]];
            }

    //记录答案
    int diff = 1e9, ans1, ans2;
    for (int k = 0; k <= m * 40; k++)
        if (f[n][m][k])
        {
            int blood1 = k, blood2 = sum - k;
            if (abs(blood1 - blood2) < diff)
            {
                diff = abs(blood1 - blood2);
                ans1 = min(blood1, blood2);
                ans2 = max(blood1, blood2);
            }
        }
    cout << ans1 << ' ' << ans2 << endl;
    return 0;
}

到了这里,关于洛谷 P1489 猫狗大战【背包+bool类型dp】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法第十五期——动态规划(DP)之各种背包问题

    目录 0、背包问题分类 1、 0/1背包简化版 【代码】 2、0/ 1背包的方案数 【思路】

    2023年04月09日
    浏览(31)
  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(35)
  • 动态规划(DP)---- 01背包入门详解----二维图是学会的关键

        动态规划,Dynamic Programing(简称DP),个人认为是一种 算法思想 , 用来解决多阶段多层次的选择问题,把一个复杂的问题分解成每个小块的子问题然后一个个解决来找到最优解。     DP适用 重叠子问题 和 最优子结构的性质 的问题。     DP问题范围分为 线性与非线性

    2024年02月03日
    浏览(29)
  • Leetcode动态规划篇(0-1背包问题一维和二维dp实现)

    🤗专栏:每日算法学习 💬个人主页:个人主页 🤓情况描述:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。每一件物品其实只有两个状态,取或者不取。

    2023年04月09日
    浏览(32)
  • 【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析

    动态规划就像是解决问题的一种策略,它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题,并将每个小问题的解保存起来。这样,当我们需要解决原始问题的时候,我们就可以直接利用已经计算好的小问题的解,而不需要重

    2024年02月03日
    浏览(32)
  • 手把手教你用Yolov5 (v6.2) 训练分类模型 基于《Kaggle猫狗大战》案例

    在8月17日晚上, YOLOv5 官方发布了 v6.2 版本, v6.2 版本支持分类模型训练、验证、预测和导出; v6.2 版本的推出使得训练分类器模型变得超级简单! 下一个版本 v6.3 计划于9月发布,将为 YOLOv5 带来官方实例分割支持,今年晚些时候将发布一个主要的 v7.0 版本,更新所有3个任务

    2024年01月18日
    浏览(46)
  • 【洛谷】采药(01背包问题)

      将二维数组优化为一维数组 在上面的过程中,我们发现dp[i][j] = max(dp[i - 1][j], dp[i - 1][ j - times[i] ] + val[i]); 也就是第 i 行的数据只与第 i-1 行的数据有关,因此我们存储的 i-2 ,i-3 等都是无效的数据,那么我们可以将二维数组优化成一维数组,利用一维数组里原本存储的第

    2024年02月16日
    浏览(29)
  • 洛谷 装箱问题 01背包 java

    🍑 OJ专栏 🍑 装箱问题 有一个箱子容量为 V V V ,同时有 n n n 个物品,每个物品有一个体积。 现在从 n n n 个物品中,任取若干个装入箱内(也可以不取),使箱子的剩余空间最小。输出这个最小值。 第一行共一个整数 V V V ,表示箱子容量。 第二行共一个整数 n n n ,表示物

    2024年02月04日
    浏览(34)
  • python布尔类型(bool)

    bool类是int类的子类。 python中提供了 bool 类型来表示真(对)或假(错),并分别用 Ture (真或对)或 False (假或错)来表示,在python中,是明确区分大小写的,即首字母一定要大写,不然解释器会报错的 True False class \\\'bool\\\' class \\\'bool\\\' bool类型只有Ture和False两个实例,且

    2024年02月08日
    浏览(34)
  • 【算法宇宙——在故事中学算法】背包dp之完全背包问题

    学习者不灵丝相传,而自杖明月相反,子来此事却无得失。 尽管计算机是门严谨的学科,但正因为严谨,所以要有趣味才能看得下去。在笔者的前几篇算法类文章中,都采用了以小故事作为引入的方式来介绍算法,但在回看的时候发现学术味还是太浓了,完全没有想看下去的

    2023年04月20日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包