zoukankan      html  css  js  c++  java
  • Timus-1005. Stone Pile-01背包

    传送门:http://acm.timus.ru/problem.aspx?space=1&num=1005

    参考:https://www.cnblogs.com/yinzm/p/6629222.html

    题意

    给出许多石子堆,问能分成怎样的两堆,使得两堆差距最小;

    思路:我看到题解后才意识到以前可能写过类似的,竟然是01背包;

    看完题目之后,我们可以了解一下数据的规模,最多就20个石头,所以我们可以列出我们能够解题的一些方法:

    • 直接深度优先搜索,暴力得到每一种划分方法
    • 二进制枚举,这也是一种暴力求解方法
    • 将题目转化为01背包问题,动态规划求解

    结合题目时间限制,我们最终选择第三种方法。所以现在来重点讲解下,这个题目需要怎么转化为01背包问题的。
    首先,将石头划分成AB两堆,那么我们相当于从一堆石头里面挑选出若干个石头出来。对于每一块石头都有挑选或者不挑选两种选择。这就有点像01背包问题了,但是目前还不确定如何用01背包来求解。题目要求我们求解两堆石头的最小差,如果石头是可以掰开的,那么最理想的状态当然是两堆石头的重量都是原始那堆石头重量的一半avg,但是现实不是那么完美的,我们不能将石头掰开揉碎,而且很有可能最终的最好结果确实是一堆重一堆轻。
    假设最优的结果是一堆石头重量为A,另外一堆是B,那么AB两者可能是其中一个大于等于avg,另外一个是小于等于avg。我们现在需要使|A-B|最小,那么最好是AB越靠近avg越好,这就相当于我们拿一个最大承重为avg的袋子去装石头,最多能装多少重量的石头。这就是一个01背包问题了。接下来我们只要求出这个背包问题的解,那么最后的差也就能够计算出来了。

    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e6+5;
    int n;
    int a[22];
    int dp[maxn];
    int ab(int x)
    {
        return x >0? x:-x;
    }
    int main()
    {
        scanf("%d",&n);
        int m=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),
            m+=a[i];
        int ave = m/2;
        //cout<<m<<endl;
        for(int i=1;i<=n;i++)
        {
            for(int j=ave;j>=0;j--)
            {
                if(j>=a[i])
                {
                    dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
                }
            }
        }
        //cout<<dp[ave]<<endl;
        int ans = ab(dp[ave]-(m-dp[ave]));
        printf("%d
    ",ans);
        //sort(a+1,a+1+n);
    
        return 0;
    }
  • 相关阅读:
    贝叶斯思想的实质之我见
    强化学习基础概念理解
    Thinkpad x200用户只能放弃生化危机5(PC版), 希望能全速运行星际争霸2!
    This is it
    今天自己掏腰包去买联通iPhone有几位?
    今天是我的生日:)
    2009已经到来 / 2009 Just the Beginning
    好评如潮的PS3游戏《抵抗2 Resistance2》你玩了吗?
    生化危机5 / BIOHAZARD5 简直就是一款完美的印钞机?(+2009.4.9)
    一部好电影《第九区 District 9》
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/8667053.html
Copyright © 2011-2022 走看看