今天做的两道DP和我以前做的不同,以前没试过换个变量来当作背包的容量,前面一道题奠定了这题的基础,这道题一看见的时候就知道用支票的个数来当容量,这道题有点题意不清,没看discuss的时候我也把题意理解错了,它说单项物品不超过600元其实是此类物品不超过600元,这道题也不能完全按照Robberies来做,这里有金额q的限制.
转移方程为d[i]=max(d[j])+p[i]; 1=<j<i;
代码:
#include<iostream>
#include<cmath>
using namespace std;
double dp[35],p[35];
int main()
{
int n,flag,i,j,m;
double q,sum,temp,d[100];
char ch;
while( scanf("%lf%d",&q,&n)&&n){
j=1;
for( i=1; i<=n; i++){
scanf("%d",&m);
flag=1;
sum=0;
memset(d,0,sizeof(d));
while( m--){
scanf(" %c:%lf",&ch,&temp);
d[ch-'A']+=temp; //是同类物品的累计
if( ch!='A'&&ch!='B'&&ch!='C'||d[ch-'A']>600){
flag=0;
}
sum+=temp;
}
if( sum<=1000&&flag)
p[j++]=sum;
}
n=j-1;
memset(dp,0,sizeof(dp));
double ret=0;
for( i=1; i<=n; i++){
double mx=0.0;
for( j=1; j<i; j++)
if( dp[j]>mx&&dp[j]+p[i]<=q)
mx=dp[j];
dp[i]=mx+p[i];
if( ret<dp[i])
ret=dp[i];
}
printf("%.2lf\n",ret);
}
return 0;
}
或者把最后的关键代码改成比较普通的0/1背包就比较好理解了。
for( i=1; i<=n; i++){
for( j=n; j>0; j--){
temp=dp[j-1]+p[i];
if( temp<=q&&temp>dp[j])
dp[j]=temp;
}
}