历尽千辛万苦 终于把完全背包弄明白了,由此可鉴,对于动态规划的子结构 还是不太熟悉。加油!!!吖飒 相信自己!我可以的。。。
题意:
选择硬币使瓶子满(W),且value最小。
看懂题就知道 是个完全背包问题。
对于完全背包,
二维解法:
假定dp[i][j],i代表放置了i个硬币重量是j。子结构就是dp[i-1][j-w[j]]+p[j](少放一个硬币,重量是当前重量减该硬币的重量),
dp[i][w]中最小的值即为解。
由于每个硬币可以放很多次,要多加一个循环,w[j]分解成(k*w[j]),p[j]分解成k*p[j](1=<k<=W/w[j])即每个硬币分解成很多个重量价值一样的硬币。
初始化问题,当W=0时,dp[i][0]=0;
另计:这种解法 有没有很像多重背包呢、、、、像, 很像!
一维解法:
用心观察会发现,dp[i][j-w[i]]的j-w[i]就代表着i-1的状态。dp[j]与dp[j-w[i]]的关系就对应着i与i-1的关系。即dp[j]=min(dp[j],dp[j-w[i-1]]+p[i-1]);
初始化,dp[0][0]=0;
一维解法的优化:
由于dp[i][j],i代表放置了i个硬币重量是j,i-1就是少放一个的情况,假设无论之前是否放过,即无论之前放置了几个某硬币,还可以继续放置。简化为了真正的完全背包(与0-1背包的区别就在于0-1背包只能放置一个,前面放过的不能再放所以必须n-1)
状态转移方程:dp[i]=min(dp[i],dp[i-w[i]]+p[i]);
代码:
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
struct info
{
int p;
int w;
}N[505];
int dp[10001];//物品重j
//题意是求j为某个值时是否可行,可行输出最小的value
int min(int a,int b)
{
return a>b?b:a;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int i,j,k;
int Min=100000000;
scanf("%d%d",&i,&j);
int W=j-i;
int n;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&N[i].p,&N[i].w);
/*二维解法很可能超时
for(i=0;i<=n;i++)
for(j=1;j<=W;j++)
{dp[i][0]=0;dp[i][j]=100000000;}
for(i=1;i<=n;i++)
{
for(j=N[i-1].w;j<=W;j++)
{
for(k=N[i-1].w;k<=j;k+=N[i-1].w)
{
dp[i][j]=min(dp[i][j],dp[i-1][j-k]+k/N[i-1].w*N[i-1].p);
if(j==W&&Min>dp[i][j]) Min=dp[i][j];
}
}
}*/
//由二维简化成一维数组
/*for(j=1;j<=W;j++)
dp[j]=100000000;
dp[0]=0;
for(i=1;i<=n;i++)
{
for(j=N[i-1].w;j<=W;j++)
{
for(k=N[i-1].w;k<=j;k+=N[i-1].w)
{
dp[j]=min(dp[j],dp[j-k]+k/N[i-1].w*N[i-1].p);
}
}
}*/
for(j=1;j<=W;j++)
dp[j]=100000000;
dp[0]=0;
for(i=0;i<n;i++)
{
for(j=N[i].w;j<=W;j++)
dp[j]=min(dp[j],dp[j-N[i].w]+N[i].p);
}
if(dp[W]<100000000)
printf("The minimum amount of money in the piggy-bank is %d.\n",dp[W]);
else
printf("This is impossible.\n");
}
return 0;
}
顺势我又写了个多重背包的题,其实很像完全背包。
懂了完全背包的。。。。多重的小case(仅指该题、、、、)
题意:
不用我说的 汉语 、、、、果断不解释
详见代码吧
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
struct info
{
int p;//重量
int w;//价格
int c;//数量
}N[105];
int dp[101][101];//放i种物品重j
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int i,j,k;int W,n;
int Min=0;
scanf("%d%d",&W,&n);
for(i=0;i<n;i++)
scanf("%d%d%d",&N[i].w,&N[i].p,&N[i].c);
for(i=0;i<=n;i++)
for(j=1;j<=W;j++)
dp[i][j]=0;
for(i=1;i<=n;i++)
{
for(j=1;j<=W;j++)
{
for(k=0;k<=N[i-1].c;k++)
{
if(j>=k*N[i-1].w) dp[i][j]=max(dp[i][j],dp[i-1][j-k*N[i-1].w]+k*N[i-1].p);
if(Min<dp[i][j]) Min=dp[i][j];
}
}
}
printf("%d\n",Min);
}
return 0;
}
分享到:
相关推荐
ACM HDU 2000->2099 解题报告 ACM HDU 2000->2099 解题报告 ACM HDU 2000->2099 解题报告
HDU 1010-2500解题报告,ACMer可以借鉴一下
hdu2000-2014ac代码,虽然只有几道,但都是简单的
ACM入门的课件适合于那些想要学习的ACM,提高自己编程能力的。
hdu-acm源代码(上百题)hdu-acm源代码、hdu-acm源代码hdu-acm源代码
杭州电子科技大学online judge (hdu)第十一卷 2000 - 2099 题目集 doc 格式的,希望大家喜欢!
解题报告|ACM|程序设计参考程序以及题目的分析
ACM程序设计题目分析以及AC的源码
ACM题库,一些题目和答案,以及解题报告,传上来共享
最精准的答案(本人做对的题目拿上来给大家呈现)!不要忘记是C++编的
杭电OnlineJudge 200-2099的解题报告
我去年暑假花了5天,把杭电ACM网站上2000到2099这100道题全AC了,又花了10来天精心写解题报告。 里面包括题目、解题思路、编程技巧以及参考源码。所有代码都是使用C/C++写的。 最近整理资料时无意间发现,打包...
HDU的1250,主要是利用高精度加法,但是代码有点繁琐,效率不是很高
HDU 里面的2000~2099道题目的源码。谢谢支持
背包问题的模板,可以解决各类背包问题,根据问题需要修改参数即可。试用于ACM初学者。
杭电ACM2000-2099题的解题报告