哈理工OJ2252 世界 (完全背包变形)

22 篇文章 1 订阅

完全背包和0-1背包并不是很难的DP题.

很多裸的完全背包和0-1背包的题都是可以用模板秒过的~

新手毕竟还是新手 还是遇到了小小的变形题0.0

直接就给跪了~

首先介绍一下0-1背包和完全背包是啥子东西~

0-1背包是指给你一个给定容积的背包 然后给你很多物品 尽量装物品 (每个物品只能装或不装)使最后价值最高...

完全背包是指给你一个给定容积的背包 然后给你很多物品 尽量装物品 (每个物品可以多次装)(根据题意来看)使最后价值最高...

这里今天遇到了个变形~还算是比较简单的一种变形吧(既然都跪了还装B(简单你奶奶个球)).

这里先贴上题目:


世界
Time Limit: 10000 MSMemory Limit: 32768 K
Total Submit: 78(21 users)Total Accepted: 24(17 users)Rating: Special Judge: No
Description

世界是一个非常软弱的女孩子,会在关键的时刻临阵退缩呢。你为了帮助她,让她去争取自己的幸福

,就要给她注入叫做勇气的东西!注入不同数量的勇气的花费是不一样的,那么让世界的勇气值大于

等于m的最少花费是多少呢?

Input

输入数据的第一行包括了一个整数T,表示数据的组数。

每组数据的第一行,包括了两个整数n(1≤n≤100)m(1≤m≤1000),表示勇气的种类和世界需要的勇气值。

接下来的n行,每行包括两个整数costi(1≤costi≤10)wi(1≤wi)分别表示,第i种勇气的花费和产生的勇气值。每种可以产生勇气的药剂有无限个。

Output
每组数据的输出包括一行,表示最小的花费。
Sample Input
2
1 2
10 3
2 10
100 10
1 1

Sample Output

10

10

Source
“尚学堂杯”2015级程序设计竞赛(10月)热身赛
Author
TwIStOy

详解这个题之前 先贴上完全背包模板一份:


        for(int i=0;i<n;i++)
        {
            for(int j=v;j>=a[i].w;j--)
            {
                dp[j]=max(dp[j],dp[j-a[i].w]+a[i].val);
            }
        }
这里dp数组里边存的值是表示价值val.而w则表示这个物品所占的容积 v表示背包的容积

当这里的变量改变了之后 就应该换成这样的模板:


struct wupin
{
    int cost,val;//花费和产生的勇气值.
}a[121212];
        for(int i = 0; i < n; i++)
        {
            for(int j = a[i].val;j<m;j++)
            {
                if(dp[j-a[i].val]+a[i].cost<dp[j])//最小花费 所以要小于号
                dp[j] = dp[j-a[i].val]+a[i].cost;
            }
        }


这个时候细心的读者会问 如果你的状态转移方程这么写的话 第一组样例都过不了 你个逗比~

是的~~确实是第一组样例都过不了 所以这个题叫做完全背包的变形题~

如果真的就这么简单的改改变量就能A题的话..那我就成天搞模板算了~

这个时候就要解决这个问题了~

拿第一组样例来看 产生的勇气值多出m 这必然是好的 越多勇气越多爱情~0.0

但是如果想解决这个问题就要改变主体算法中第二个for循环里边控制循环次数的变量m

这个时候就要考虑了~m到底变成什么好呢?回头读读题 1000的m100的n大不了劳资把m改成1000*100壳吧~最大值 嘎嘣脆~~~~!!!

那么问题来了 AC了吗~?答案是明确的 没有~~~~~~~

这个时候就要继续考虑了~如果1000*100不行的话 那么改成输入的时候找max勇气值吧  用它替换掉m不就可以了~~呵呵~~~这种思路也是比较天真的~

这个和m的问题一样 总要有超过max的时候出现...

所以还是要继续考虑...

我们的目的是达到m 大于等于m

我们还能找到变量中val最大值

如果当前装入的东西差一点点就满足了m勇气值的时候 正好恰巧装max勇气值那件物品就能打到耗用量最小的时候 我们就得到了最大的范围

m+max.

这个时候整个思路就清晰了~

这里贴上核心代码


        for(int i = 0; i < n; i++)
        {
            for(int j = a[i].val;j<m+mx;j++)
            {
                if(dp[j-a[i].val]+a[i].cost<dp[j])
                dp[j] = dp[j-a[i].val]+a[i].cost;
            }
        }


之后就是主干磨磨唧唧的部分了 

#include<stdio.h>
#include<string.h>
using namespace std;
struct wupin
{
    int cost,val;
}a[121212];
int dp[121212];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        int mx=-0x1f1f1f1f;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&a[i].cost,&a[i].val);
            if(a[i].val>mx)mx=a[i].val;
        }
        for(int i=1;i<m+mx;i++)
        {
            dp[i]=0x1f1f1f1f;
        }
        dp[0]=0;
        for(int i = 0; i < n; i++)
        {
            for(int j = a[i].val;j<m+mx;j++)
            {
                if(dp[j-a[i].val]+a[i].cost<dp[j])
                dp[j] = dp[j-a[i].val]+a[i].cost;
            }
        }
        int output=0x1f1f1f1f;
        for(int i=m+mx-1;i>=m;i--)
        {
            if(output>dp[i])output=dp[i];
        }
        printf("%d\n",output);
    }
}


如果有理解不太对的地方希望大家指出~~~~~





  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值