zoukankan      html  css  js  c++  java
  • POJ 3260 多重背包+完全背包

      前几天刚回到家却发现家里没网线 && 路由器都被带走了,无奈之下只好铤而走险尝试蹭隔壁家的WiFi,不试不知道,一试吓一跳,用个手机软件简简单单就连上了,然后在浏览器输入192.168.1.1就能看到他的路由器的一切信息,包括密码,然后打开笔记本……好了,废话不多说,能连上网后第一时间当然是继续和队友之前约好的训练了。

      今天翻看到之前落下的一道混合背包题目,然后在草稿本上慢慢地写递推方程,把一些细节细心地写好…(本来不用太费时间的,可是在家嘛,一会儿妈走来要我教她玩手机,一会儿有一个亲戚朋友来……简直无语了,程序猿最讨厌被人打断的!虽说我不是码农)然后,这道题,细心分析后,发现它是多重背包+完全背包的。

      首先,可以先顺着推出 John手中的coin能拼凑出的币值的最小币数,即设dp[i][j]为前 i 种coin凑出币值 j 时需要的最小币数,很明显,dp[i][j]= min(dp[i-1][j], dp[i][j-coin[i]]+1) 的递推方程很容易想到,但是,这个方程在使用前需要满足很多情况,具体的细节就看代码了(全部都进行了空间优化,其中need数组表示前 i 种coin凑出币值 j 需要的最小币数时,需要的coin[i]的数量),因为之前看过《挑战》中多重背包的实现,所以这个稍微变化一下也不是很难了。

      然后,到了收银员找币时的情况,因为题目中说了她会提供无限的零钱,所以此时就是完全背包了,注意好计算顺序即可:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 typedef long long LL;
     6 const int maxn= 10000;
     7 
     8 int dp[maxn+3], coin[103],num[103], need[maxn+3];
     9 
    10 int main(){
    11     int n,t,i,j;
    12     while(~scanf("%d%d",&n,&t)){
    13         for(i=1; i<=n; ++i)
    14             scanf("%d",coin+i);
    15         for(i=1; i<=n; ++i)
    16             scanf("%d",num+i);
    17         memset(dp,-1,sizeof(dp));
    18         dp[0]= 0;
    19         for(i=1; i<=n; ++i){
    20             memset(need,0,sizeof(need));
    21             for(j=0; j<=maxn; ++j)
    22                 if(j>=coin[i]&& dp[j-coin[i]]!= -1 && need[j-coin[i]]<num[i]){
    23                     if(dp[j]== -1 || dp[j]> dp[j-coin[i]]+1){
    24                         dp[j]= dp[j-coin[i]]+1;
    25                         need[j]= need[j-coin[i]]+1;
    26                     }
    27                 }
    28         }
    29         for(i=1; i<=n; ++i)
    30             for(j=maxn-coin[i]; j>=0; --j)
    31                 if(dp[j+coin[i]]!= -1){
    32                     if(dp[j]== -1)    dp[j]= dp[j+coin[i]]+1;
    33                     else    dp[j]= min(dp[j],dp[j+coin[i]]+1);
    34                 }
    35         printf("%d
    ",dp[t]);
    36     }
    37     return 0;
    38 }
    View Code

      因为一开始没用到need数组所以调试了一会儿,然后今早起来想了想发现昨晚写的need数组有问题,不知是数据弱还是怎么的也能过,改了下后提交发现:

      竟然排到了16名,第一次这么前。

      后来又想了想,dp数组如果用INF而不是-1来作为凑不出币值 j 的标记的话,代码会更简单一些:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 typedef long long LL;
     6 const int INF= 0x3fffffff;
     7 const int maxn= 10000;
     8 
     9 int dp[maxn+3], coin[103],num[103], need[maxn+3];
    10 
    11 int main(){
    12     int n,t,i,j;
    13     while(~scanf("%d%d",&n,&t)){
    14         for(i=1; i<=n; ++i)
    15             scanf("%d",coin+i);
    16         for(i=1; i<=n; ++i)
    17             scanf("%d",num+i);
    18         for(j=1; j<=maxn; ++j)
    19             dp[j]= INF;
    20         dp[0]= 0;
    21         for(i=1; i<=n; ++i){
    22             memset(need,0,sizeof(need));
    23             for(j=0; j<=maxn; ++j)
    24                 if(j>=coin[i] && need[j-coin[i]]<num[i]){
    25                     if(dp[j]> dp[j-coin[i]]+1){
    26                         dp[j]= dp[j-coin[i]]+1;
    27                         need[j]= need[j-coin[i]]+1;
    28                     }
    29                 }
    30         }
    31         for(i=1; i<=n; ++i)
    32             for(j=maxn-coin[i]; j>=0; --j)
    33                 dp[j]= min(dp[j],dp[j+coin[i]]+1);
    34         printf("%d
    ",dp[t]==INF? -1:dp[t]);
    35     }
    36     return 0;
    37 }
    View Code

      虽然比起上一个慢了点可以忽略不计的时间:

      anyway,人生第一道AC掉的混合背包,值得纪念,背包问题,继续进取中~~

  • 相关阅读:
    Intellij Idea 创建Web项目入门
    使用swagger作为restful api的doc文档生成
    SpringMVC中的参数绑定总结
    Spring注解@Resource和@Autowired区别对比
    java的(PO,VO,TO,BO,DAO,POJO)解释
    java有几种对象(PO,VO,DAO,BO,POJO)
    clone项目到本地
    修改虚拟机上Linux系统的IP地址
    虚拟机下CentOS 6.5配置IP地址的三种方法
    系统重启
  • 原文地址:https://www.cnblogs.com/Newdawn/p/4269014.html
Copyright © 2011-2022 走看看