HDU 1864 最大报销额(01背包)

题目地址:点击打开链接

思路: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;
}


你可能感兴趣的:(HDU 1864 最大报销额(01背包))