01背包;感谢ZCK大佬

题目描述

学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近。

输入

输入中的第一行只有一个整数n(1≤n≤100),第二行有n个以空格分隔的整数,表示每人的体重wi(所有的wi均满足:1≤wi≤450)。

输出

输出只有一行,该行有两个整数,以一个空格分隔。第一个数表示体重较大的组的体重总和,第二个数表示体重较小的组的体重总和。

题面看上去很短,题意也很好理解:就是将n个人分成两组,在人数差不大于1的情况下使它们差最小。

用cnt表示它们的体重之和,则是使两组重量之和尽可能接近cnt / 2。那么就是在cnt / 2的空间里尽可能地使选入的人重。乍一看跟“挤牛奶”没区别,都是两维的dp其中增加一位限制人数。i,j,k三维循环,

for (int i=; i<=n; i++)
for (int j=i; j>=; j--)
for (int k=cnt; k>=a[i]; k--)
因为每个人只能选一次,所以j,k逆序

i,j,k循环


先来讲讲我最早的想法:

这是一份80,一份90的代码

初始化是f[][] = 0

在这种dp[][]方程的定义下,f[i][j]表示1..i人,凑成0..j范围内能凑成的最大重量(我知道这非常奇怪。事实上,在请教ZCK之前我甚至以为这个f[i][j]表示i个人能否凑出j。所以我发现"当f[i][j] != 0时,f[i][j] != j "这个现象时候才开始怀疑我的dp方程)

f[j][k] = max(f[j][k], f[j-1][k-a[i]]+a[i]);

在最终选取ans的时候,由于我们希望ans最接近cnt / 2,那么循环是“cnt / 2 ... 1“的,则ans = max{f[n / 2][]}。在这种情况下,不能够只判断 f[n / 2][i] 。虽然这看上去很有道理——如果n是奇数,用cnt - f[n / 2][i]就是奇数那一队的人数嘛!ZCK解释说:“f[n / 2][] 和 f[n / 2+1][] (n为奇数)是两条不同的数轴,不能保证f[n / 2][]上最接近cnt / 2的值比f[n / 2+1][]上的更优。”由于我们枚举的f[n / 2][] ≤ cnt / 2,那么对应的f[n / 2+1][]就是 ≥ cnt / 2的。有可能n / 2+1人能凑出更接近cnt / 2的!

可能会想到:既然dp时候已经把f[][cnt ... 1]都表示出来了,那么只需要在寻找ans的时候改动一下,变成这样

for (int j=cnt; j>=1; j--)
{
if (abs(cnt - 2*f[n/2][j]) < abs(cnt-2*ans))ans = f[n/2][j]
}

实际上,这样的判断只有70分。

并不是因为寻找ans的过程有问题,是因为f[][]所表示的东西不是我们想要的


这原因是初始化。

memset(f,-127,sizeof(f));  将f初始化为一个很小很小的数,这样f[i][j]表示的东西就不一样了
f[0][0]=0;  必要的

这样改了之后,只需要"cnt ... 1"判f[n / 2][]即可.

当然"cnt / 2 ... 1"判f[n / 2][], f[n / 2+1][]也可

因为我的dp方程太凌乱了……为了阿掉这题爆交共30+……


ZCK:你的dp方程到底想表示什么???直接bool不就好了吗

bool f[103][45035];

实际上,这的确是最简洁而且dp方程表示最明确的一种方法……


讲了这么多,实际上只是想说明dp方程的 定义 和 初始化 对于dp来说有多么重要。短短的一句初始语句或者在脑海中闪过一瞬的dp方程碎片,就足以上演化爆零为AC的奇迹。一个max和一个if看上去没多大差别,事实上后续的处理可能失之千里。考虑问题要仔细全面,这绝对不是一句空话。

【dp】拔河比赛的更多相关文章

  1. codevs 1959 拔河比赛--判断背包内刚好装满n/2个物品

    1959 拔河比赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 一个学校举行拔河比赛,所有的 ...

  2. codevs1959拔河比赛(二维费用背包)

    1959 拔河比赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description 一个学校举行拔河比赛,所有的人被分成了两组,每个人 ...

  3. CODEVS 1959 拔河比赛(另一版本)

    题目描述 Description 一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近. 输入描述 ...

  4. rqnoj71 拔河比赛

    题目描述 superwyh的学校要举行拔河比赛,为了在赛前锻炼大家,老师决定把班里所有人分为两拨,进行拔河因为为锻炼所以为了避免其中一方的实力过强老师决定以体重来划分队伍,尽 量保持两个队伍的体重差最 ...

  5. c 指针 及其位运算循环移动拔河比赛问题代码

    week_2_day1_7.7 周一//用字符数组 来实现 字母大小写转换#include<stdio.h>void desc( char *a ,int n){    char  *i ...

  6. [深搜]A. 【例题1】拔河比赛

    A . [ 例 题 1 ] 拔 河 比 赛 A. [例题1]拔河比赛 A.[例题1]拔河比赛 解析 模板题,选与不选 Code #include <bits/stdc++.h> #defi ...

  7. 【C/C++】拔河比赛/分组/招商银行

    题目:小Z组织训练营同学进行一次拔河比赛,要从n(2≤n≤60,000)个同学中选出两组同学参加(两组人数可能不同).对每组同学而言,如果人数超过1人,那么要求该组内的任意两个同学的体重之差的绝对值不 ...

  8. 【codevs1959】拔河比赛

    题目大意:给定一个有 N 个数的集合,将这 N 个数均分成两堆,求差值最小是多少. 题解:有关集合选数的问题,应该是背包问题,同时要求均分可知,选出的物品数目也应该是背包费用的一个维度,因此这是一个多 ...

  9. 【解题报告】[动态规划]RQNOJ - PID72 / 拔河比赛

    原题地址:http://www.rqnoj.cn/problem/72 解题思路:基本的01背包问题. 要求的就是在这些人中选出一些人,使得这些人的体重的和 不超过所有人的体重的一半 并最大. 代码: ...

随机推荐

  1. perl 打开二进制文件,并拷贝内容

    实现脚本 use strict ; my $fileName = "/Users/chenfool/Desktop/sequoiadb-大数据平台构建.pdf" ; my $out ...

  2. C语言带参宏定义和函数的区别

    带参数的宏和函数很相似,但有本质上的区别:宏展开仅仅是字符串的替换,不会对表达式进行计算:宏在编译之前就被处理掉了,它没有机会参与编译,也不会占用内存.而函数是一段可以重复使用的代码,会被编译,会给它 ...

  3. extern使用方法总结!(转)

    extern 在源文件A里定义的函数,在其它源文件里是看不见的(即不能访问).为了在源文件B里能调用这个函数,应该在B的头部加上一个外部声明: extern   函数原型: 这样,在源文件B里也可以调 ...

  4. ZooKeeper应用案例

    我们通过学习借鉴,哪些项目或应用都使用了ZooKeeper,可以了解我们的应用使用ZooKeeper是否能真正地带来价值,当然,有些项目可能也未必非常适合使用ZooKeeper,我们要批判地学习.借鉴 ...

  5. adb server version (39) doesn't match this client (40); killing...

    在启动RN项目的时候也报错,上面的错误是在adb的环境变量中的位置和android studio的sdk不是一个位置.adb是在sdk中的,所以他们应该是一致的位置 android studio的sd ...

  6. centos 7 安装node.js

    Node.js v10.x安装命令 curl --silent --location https://rpm.nodesource.com/setup_10.x | bash - Node.js v5 ...

  7. 洛谷1005(dp)

    1.不要贪,缩小区间去dp就好. 2.预处理指数. 3.__int128可还行. #include <cstdio> #include <cctype> #include &l ...

  8. 085 Maximal Rectangle 最大矩形

    给定一个填充了 0 和 1 的二进制矩阵,找到最大的只包含 1 的矩形并返回其面积.例如,给出以下矩阵:1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0返回 6 详见:http ...

  9. [已读]JavaScript高级程序设计(第2版)

    经典红皮书~~

  10. java数据类型是有符号的,那与有些无符号的如何区别

    一.首先需要明白数据类型有符号与无符号的概念 最明显的区别就是二者表示的范围不同: 无符号数中,所有的位都用于直接表示该值的大小.有符号数中最高位用于表示正负,所以,当为正值时,该数的最大值就会变小. ...