• 【dp】拔河比赛


    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=1; i<=n; i++)
        for (int j=i; j>=1; 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看上去没多大差别,事实上后续的处理可能失之千里。考虑问题要仔细全面,这绝对不是一句空话。

  • 相关阅读:
    IDEA实用教程(十一)—— 使用Maven创建JavaSE项目
    IDEA实用教程(十)—— 配置Maven的全局设置
    IDEA实用教程(九)—— 创建Servlet
    IDEA实用教程(八)—— 创建JavaWeb项目
    搭建视频解析的接口
    IDEA实用教程(七)—— IDEA的断点调试
    Elasticsearch 常用配置参数总结
    C# web api返回类型设置为json的两种方法
    asp.net MVC 中@Html.Partial,@Html.Action,@Html.RenderPartial,@Html.RenderAction区别
    CountDownLatch的使用和原理解析
  • 原文地址:https://www.cnblogs.com/antiquality/p/7991170.html
Copyright © 2020-2023  润新知