题目地址:​​点击打开链接​

思路:01背包 ,只有ABC类能报销,有别的种类也不能报销,单类的物品不能超过600,超过也不能报销,扩大100倍算的,直接小数有点麻烦,主要思想是Tianyi Cui大神写的背包九讲,本博客算法精讲类有,写一下我认为最难的吧,就是用一维数组做01背包,背包的容量是从大到小循环的,之所以这样做就是不会产生覆盖问题,因为大的背包要用上一个阶段的小的背包的数据,如果先算小容量,后面大容量使用的数据就不是上一个阶段的数据了,会导致出错,因为可能会导致相同物品放多个进去,而用一维数组做完全背包,背包的容量是从小到大循环的,因为每个物品可以放无数个,所以不会产生错误。

AC代码:

#include<stdio.h>
#include<string.h>
int visit[40];
int dp[3000100],cost[40];
int max(int a,int b)
{
return (a > b) ? a : b;
}
int main()
{
char l;
int n,i,j,m,len,sum2,money,flag;
int a,b,c;
double q,sum1;
while(scanf("%lf%d",&q,&n) && n)
{
money = (int)(q * 100);
len = 0;
memset(visit,0,sizeof(visit));//只能初始化为0,-1,true,false,不能初始化为1
memset(dp,0,sizeof(dp));
for(i=0; i<n; i++)
{
scanf("%d",&m);
a = b = c = 0;
flag = 1;
for(j=0; j<m; j++)
{
scanf(" %c:%lf",&l,&sum1);//前面一个空格;
sum2 = (int)(sum1 * 100);
if(l == 'A')
a += sum2;
else if(l == 'B')
b += sum2;
else if(l == 'C')
c += sum2;
else
flag = 0;
}
if(a + b + c <= 100000 && a <= 60000 && b <= 60000 && c <= 60000 && flag)
{
cost[len++] = a + b + c;
}
}
for(i=0; i<len; i++)//依次判断每件物品取舍的状况
{
for(j=money; j>=cost[i]; j--)//倒序是要防止产生覆盖问题,不然会造成后面大值用小值时候,小值已经改变
{
dp[j] = max(dp[j],dp[j-cost[i]] + cost[i]);
}
}
printf("%.2lf\n",dp[money] / 100.0);
}
return 0;
}