Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?
Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
Output
One integer per line representing the maximum of the total value (this number will be less than 2 31).
Sample Input
1 5 10 1 2 3 4 5 5 4 3 2 1
Sample Output
14
思路:本题只需要填表,找到背包可能得到的最大价值,v[i][j]表示前i个物品放入剩余空间为j的背包中,能得到的最大价值,如果剩余空间不够装第i个物品,即volume[i]>j,第i件物品就不能被放入,此时v[i][j]=v[i-1][j],即把前i个物品放入剩余空间为j的背包的得到的价值等于把前i-1个物品放入剩余空间为j的背包得到的价值;如果剩余空间够装第i个物品,则v[i][j]=v[i-1][j-volume[i]]+value[i],即把前i个物品放入剩余空间为j的背包的价值等于把前i-1个物品放入剩余空间为j-volume[i](原来空间是j,但放入物品i后,就只剩下j-volume[i]的空间给前i-1件物品放了)的背包中得到的价值再加上第i件物品本身的价值。本题填表用的是二维空间。
如果要压缩成一维空间,代码如下:
for(int i=1; i<=n; i++)//这里不需要用到i-1所以i从1开始
for(int j=c; j>=volume[i]; j--)
//逆序遍历,并且只遍历到当前volume[i],
//保证都是可以放下的(j>=volume[i]),那么没被遍历到的v[j]都是放不下的,
//值没有被替换和覆盖,所以是上一状态的值,也就是放入前i-1件物品时,v[j]的值。
{
v[j]=max(v[j],v[j-volume[i]]+value[i]);
}
#include <iostream>
#include <algorithm>
#define MAXN 1005
#define MAXV 1005
using namespace std;
int v[MAXN][MAXV];
int value[MAXN];
int volume[MAXN];
void FillTable(int n,int c)//n是个数,c是总容量
{
for(int i=1;i<=n;i++)
{
for(int j=0;j<=c;j++)//从0开始意味增量0也可以计算
{
if(volume[i]>j)//装不下
{
v[i][j]=v[i-1][j];//v[i-1]的状态要存在,所以i从1开始
}
else
{
v[i][j]=max(v[i-1][j],v[i-1][j-volume[i]]+value[i]);//后面的价值不一定比前面的大,要做比较
}
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(v,0,sizeof(v));
memset(value,0,sizeof(value));
memset(volume,0,sizeof(volume));
int n,c;
cin>>n>>c;//n个数,c总容量
for(int i=1;i<=n;i++)
{
cin>>value[i];//输入价值
}
for(int i=1;i<=n;i++)
{
cin>>volume[i];//输入体积
}
FillTable(n,c);
cout<<v[n][c]<<endl;
}
return 0;
}
变形
I NEED A OFFER! HDU - 1203
Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了。要申请国外的任何大学,你都要交纳一定的申请费用,这可是很惊人的。Speakless没有多少钱,总共只攒了n万美元。他将在m个学校中选择若干的(当然要在他的经济承受范围内)。每个学校都有不同的申请费用a(万美元),并且Speakless估计了他得到这个学校offer的可能性b。不同学校之间是否得到offer不会互相影响。“I NEED A OFFER”,他大叫一声。帮帮这个可怜的人吧,帮助他计算一下,他可以收到至少一份offer的最大概率。(如果Speakless选择了多个学校,得到任意一个学校的offer都可以)。
Input
输入有若干组数据,每组数据的第一行有两个正整数n,m(0<=n<=10000,0<=m<=10000)
后面的m行,每行都有两个数据ai(整型),bi(实型)分别表示第i个学校的申请费用和可能拿到offer的概率。
输入的最后有两个0。
Output
每组数据都对应一个输出,表示Speakless可能得到至少一份offer的最大概率。用百分数表示,精确到小数点后一位。
Sample Input
10 3 4 0.1 4 0.2 5 0.3 0 0
Sample Output
44.0%
Hint
You should use printf("%%") to print a '%'.
思路:
属于0/1背包问题,题目要求的是至少得到一份offer的最大概率,可以转化为求一份offer都得不到的最小概率。p(得不到某份offer)=1-p(得到某份offer)。dp[j]表示用剩下j万元申请i个学校的offer不成功的概率,当cost[i]>j,说明剩下j万元申请不到第i个学校的offer,dp[0~j]保留上一次循环的结果,dp[j~i]更新为dp[j]和dp[j-cost[i]]*(1.0-chance[i])中的较小值。
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int cost[10005];
double chance[10005];
double dp[10005];
int main()
{
int n,m;
while(cin>>n>>m&&n+m)//m学校n钱
{
for(int i=0;i<=n;i++)
{
dp[i]=1.0;
}
for(int i=1; i<=m; i++)
{
cin>>cost[i]>>chance[i];
}
for(int i=1; i<=m; i++)
for(int j=n; j>=cost[i]; j--)
{
dp[j]=min(dp[j],dp[j-cost[i]]*(1.0-chance[i]));
}
printf("%.1f%%\n",(1.0-dp[n])*100);
}
return 0;
}