題意:我們需要去取款機取錢,而取款機內錢的種類和數量是有限的,最後要求出我們最多能取到多少錢。
思路:很明顯的多重揹包問題。對於這個題最普通的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;
}