题意:我们需要去取款机取钱,而取款机内钱的种类和数量是有限的,最后要求出我们最多能取到多少钱。
思路:很明显的多重背包问题。对于这个题最普通的01背包限制次数的写法是一定会超时的,所以我们需要去优化,两个优化方法,一个是二进制优化,另一个是完全背包限制次数。这3种方法的代码都会在后面发出来。
TLE代码(01背包限制次数)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
int dp[100010];
int main()
{
int m,i,j,n,k;
int bill[1100],money[1100];
while(~scanf("%d",&m))
{
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d%d",&bill[i],&money[i]);
}
for (i=0;i<n;i++)
{
for(j=0;j<bill[i];j++)
{
for(k=m;k>=money[i];k--)
{
dp[k]=max(dp[k],dp[k-money[i]]+money[i]);
}
}
}
printf("%d\n",dp[m]);
}
return 0;
}
AC 二进制优化:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
int dp[100010];
int w[1000100];
int main()
{
int m,i,n,k;
int bill[1100],money[1100];
while(~scanf("%d",&m))
{
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d%d",&bill[i],&money[i]);
}
int t=0;
for(i=0;i<n;i++)
{
int sum=1;
while(sum<bill[i])
{
w[t++]=sum*money[i];
bill[i] -= sum;
sum*=2;
}
w[t++]=bill[i]*money[i];
}
for (i=0;i<t;i++)
{
for(k=m;k>=w[i];k--)
{
dp[k]=max(dp[k],dp[k-w[i]]+w[i]);
}
}
printf("%d\n",dp[m]);
}
return 0;
}
AC 完全背包限制次数
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
int dp[100010];
int num[100010];
int w[1000100];
int main()
{
int m,i,n,k;
int bill[1100],w[1100];
while(~scanf("%d",&m))
{
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d%d",&bill[i],&w[i]);
}
for (i=0;i<n;i++)
{
memset(num,0,sizeof(num));
for(k=w[i];k<=m;k++)
{
if(dp[k]<dp[k-w[i]]+w[i]&&num[k-w[i]]<bill[i]) //状态数量限制
{
dp[k]=dp[k-w[i]]+w[i];
num[k]=num[k-w[i]]+1;
}
}
}
printf("%d\n",dp[m]);
}
return 0;
}