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

本文介绍了一道关于最大报销额的算法题目,旨在通过01背包问题求解在给定额度下可报销的最大金额。文章详细阐述了输入处理、有效性验证及如何利用动态规划解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目网址:最大报销额

最大报销额

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Problem Description
现有一笔经费可以报销一定额度的发票。允许报销的发票类型包括买图书(A类)、文具(B类)、差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600元。现请你编写程序,在给出的一堆发票中找出可以报销的、不超过给定额度的最大报销额。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行包含两个正数 Q 和 N,其中 Q 是给定的报销额度,N(<=30)是发票张数。随后是 N 行输入,每行的格式为:
m Type_1:price_1 Type_2:price_2 ... Type_m:price_m
其中正整数 m 是这张发票上所开物品的件数,Type_i 和 price_i 是第 i 项物品的种类和价值。物品种类用一个大写英文字母表示。当N为0时,全部输入结束,相应的结果不要输出。
 

Output
对每个测试用例输出1行,即可以报销的最大数额,精确到小数点后2位。
 

Sample Input
  
200.00 3 2 A:23.50 B:100.00 1 C:650.00 3 A:59.99 A:120.00 X:10.00 1200.00 2 2 B:600.00 A:400.00 1 C:200.50 1200.50 3 2 B:600.00 A:400.00 1 C:200.50 1 A:100.00 100.00 0
 

Sample Output
  
123.50 1000.00 1200.50
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   2955  1203  1231  1087  2844 


题意:Q为报销额度 N为发票张数  下面N行每行为一张发票,当发票中有以下几种情况时不予报销①A,B,C某一类的金额超过了600(注意:2 A:200 A:500也是不可以的)②出现了不是A,B,C的类③发票总金额超过1000元,问在Q的报销额度下你最大能报销多少钱?
思路:01背包问题    输入会有一点小麻烦,我立了一个FLAG来标志是否出现了1 2两种情况,如果盖章发票没出现1,2情况也符合三的要求,那么盖章发票有效可以报销,我们就把它记录到一个a数组里面。这样很明显就是一个01背包问题了,背包容量为Q,物品为可以的报销的发票即a数组中的东西,每件物品的价值和花费均为发票金额。
但是现在还有一个问题这些金额会有小数,不能像01背包那样作为下标,所以我们可以将这些金额都扩大100倍(1000会dp数组超内存),这样就可以跟01背包一样处理了。
#include <bits/stdc++.h>
using namespace std;  
int N,M,a[35],dp[3000005],v;
double Q;
int main()  
{
    while(~scanf("%lf%d",&Q,&N)&&N)
    {
    	memset(dp,0,sizeof(dp));
    	int num=0;v=Q*100;
    	for(int i=0;i<N;i++)
    	{
    		scanf("%d",&M);
    		bool flag=true;char c;double sum=0.0,s,aa=0,bb=0,cc=0;
    		for(int j=0;j<M;j++)
    		{
    			scanf(" %c:%lf",&c,&s);
    			if(c=='A')
    			{
    				aa=aa+s;
				}
				else if(c=='B')
				{
					bb=bb+s;
				}
				else if(c=='C')
				{
					cc=cc+s;
				}
				else
				{
					flag=false;
				}
    			if(aa>600.00||bb>600.00||cc>600.00) flag=false;
    			sum+=s;
			}
			if(flag&&sum<=1000.00) a[num++]=sum*100;
		}
		for(int i=0;i<num;i++)
		{
			for(int j=v;j>=a[i];j--)
			{
				dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
			}
		}
		printf("%.2lf\n",(double)dp[v]/100.0);
	}
    return 0;  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值