题意:
有一些钱币,给出它们的面额和数量,求出不超过V的最大的和
思路:多重背包直接上。但是不优化要超时
把这些钞票看作是独立的,转化为01背包来做。
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<climits>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cfloat>
using namespace std;
int dp[100005],w[1005],num[1005],w1[1005];
int main()
{
int N,i,j,V,k,cnt;
while(scanf("%d%d",&V,&N)==2)
{
memset(dp,0,sizeof(dp));
memset(num,0,sizeof(num));
memset(w,0,sizeof(w));//初始化
for(i=1;i<=N;i++)
scanf("%d%d",&num[i],&w[i]);
cnt=1;
for(i=1;i<=N;i++)
{
k=1;
while(num[i]>0)
{
if(k>num[i])k=num[i];
num[i]-=k;
w1[cnt]=k*w[i];//把钞票的面额放在另一个数组,数量为1
//最好是另开一个数组,以免赋值的时候操作不当,值被覆盖
cnt++;
k*=2;
}
}
for(i=1;i<cnt;i++)//01背包
{
for(j=V;j>=w1[i];j--)
{
if(dp[j]<dp[j-w1[i]]+w1[i])
{
if(dp[j-w1[i]]+w1[i]<=V)
dp[j]=dp[j-w1[i]]+w1[i];
}
}
}
printf("%d\n",dp[V]);
}
return 0;
}
还有另一种骚操作,但是难理解
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<climits>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cfloat>
using namespace std;
int dp[100005],w[1005],num[1005];
int main()
{
int N,i,j,V,k,nu;
while(scanf("%d%d",&V,&N)==2)
{
for(i=1;i<=N;i++)
scanf("%d%d",&num[i],&w[i]);
memset(dp,0,sizeof(dp));
for(i=1;i<=N;i++)//第一重循环
{
if(num[i]<V/w[i])nu=num[i];
else nu=V/w[i];
k=1;
while(nu>0)//第二重
{
if(k>nu)k=nu;
nu-=k;
for(j=V;j>=w[i]*k;j--)//第三重
{
if(dp[j]<dp[j-k*w[i]]+k*w[i])
{
if(dp[j-k*w[i]]+k*w[i]<=V)
//是小于等于,别忘了可以相等
dp[j]=dp[j-k*w[i]]+k*w[i];
}
}
k*=2;
}
}
printf("%d\n",dp[V]);
}
return 0;
}