【九度】题目1025:最大报销额

108 篇文章 0 订阅
102 篇文章 5 订阅

题目地址: http://ac.jobdu.com/problem.php?pid=1025
题目描述:
        现有一笔经费可以报销一定额度的发票。允许报销的发票类型包括买图书(A类)、文具(B类)、差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600元。现请你编写程序,在给出的一堆发票中找出可以报销的、不超过给定额度的最大报销额。
输入:
        测试输入包含若干测试用例。每个测试用例的第1行包含两个正数 Q 和 N,其中 Q 是给定的报销额度,N(N<=30)是发票张数。随后是 N 行输入,每行的格式为:
        m Type_1:price_1 Type_2:price_2 ... Type_m:price_m
        其中正整数 m 是这张发票上所开物品的件数,Type_i 和 price_i 是第 i 项物品的种类和价值。物品种类用一个大写英文字母表示。当N为0时,全部输入结束,相应的结果不要输出。
输出:
         对每个测试用例输出1行,即可以报销的最大数额,精确到小数点后2位。
样例输入:
        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
样例输出:
        123.50
        1000.00
        1200.50
来源:
        2007年浙江大学计算机及软件工程研究生机试真题
答疑:
        解题遇到问题?分享解题心得?讨论本题请访问:http://t.jobdu.com/thread-7749-1-1.html
【解题思路】
        其实是01背包,但是在处理基础数据的时候比较复杂。
        有以下几种限制。
        1、发票必须是A、B、C中的其中一种或者多种,如果出现D、E等等,这张发票就作废了。
        2、每张发票上可能开多种类别,但是每种类别钱数不能超过600,总和不得超过1000。
        这样处理完毕以后,就知道有多少张发票可以使用。
        接下来,问题就简化为有一堆待报销的发票,最多可以报销q,求在限制范围内,可以报销的最大额是多少。
        发票要么报销,要么不报销,典型的01背包。
        但是,还得注意,因为有类型的限制,有可能会出错。
        不妨将double乘倍数取整,这样处理起来方便又不容易出错,这是在很多题目中所使用的技巧之一。
Java AC

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;
  
public class Main {
    /*
     * 1025
     */
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            double q = scanner.nextDouble();
            int n = scanner.nextInt();
            if (n == 0) {
                break;
            }
            List<Integer> numList = new ArrayList<Integer>();
            while (n > 0) {
                double A = 0;
                double B = 0;
                double C = 0;
                int valid = 0;
                int m = scanner.nextInt();
                while (m > 0) {
                    String a = scanner.next();
                    String typeArr[] = a.split(Pattern.quote(":"));
                    double price = Double.parseDouble(typeArr[1]);
                    if (typeArr[0].equals("A")) {
                        A += price;
                    }else if (typeArr[0].equals("B")) {
                        B += price;
                    }else if (typeArr[0].equals("C")) {
                        C += price;
                    }else {
                        valid = 1;
                    }
                    m--;
                }
                  
                if (valid == 0 && A <= 600.00 && B <= 600.00 && C <= 600.00) {
                    double total = A + B + C;
                    if (total <= 1000.00 && total <= q) {
                        numList.add((int) (total*100));
                    }
                }
                n--;
            }
            int len = numList.size();
            int hunq = (int) (q * 100);
            int dp[] = new int[hunq + 1];
            for (int i = 0; i < len; i++) {
                int tempNum = numList.get(i);
                for (int j = hunq; j >= tempNum; j--) {
                    dp[j] = Math.max(dp[j], dp[j - tempNum] + tempNum );
                }
            }
            double res = (double)(dp[hunq]/100.00);
            System.out.printf("%.2f\n" , res);
        }
    }
}
/**************************************************************
    Problem: 1025
    User: wangzhenqing
    Language: Java
    Result: Accepted
    Time:420 ms
    Memory:49096 kb
****************************************************************/

C++ AC

#include <stdio.h>
const int maxn = 32;
int n,i;
double q;
int numArr[32];
int max(int a, int b){
    return a > b ? a : b;
}
int main(){
    while(scanf("%lf %d",&q,&n) != EOF){
        if(n == 0){
            break;
        }
        int len = 0;
        while (n > 0) {
            double A = 0;
            double B = 0;
            double C = 0;
            double price;
            int valid = 0;
            char c;
            int m;
            scanf("%d",&m);
            while (m > 0) {
                getchar();
                scanf("%c:%lf", &c, &price);
                if (c == 'A') {
                    A += price;
                }else if (c == 'B') {
                    B += price;
                }else if (c == 'C') {
                    C += price;
                }else {
                    valid = 1;
                }
                m--;
            }  
            if (valid == 0 && A <= 600.00 && B <= 600.00 && C <= 600.00) {
                double total = A + B + C;
                if (total <= 1000.00 && total <= q) {
                    numArr[len] = (int)(total*100);
                    len++;
                }
            }
            n--;
        }
        int hunq = (int) (q * 100);
        int *dp = new int[hunq + 1];
        for(i = 0; i < hunq+1; i++){
            dp[i] = 0;
        }
        for (i = 0; i < len; i++) {
            int tempNum = numArr[i];
            for (int j = hunq; j >= tempNum; j--) {
                dp[j] = max(dp[j], dp[j - tempNum] + tempNum );
            }
        }
        double res = (double)(dp[hunq]/100.00);
        printf("%.2lf\n",res);
    }
    return 0;
}
/**************************************************************
    Problem: 1025
    User: wangzhenqing
    Language: C++
    Result: Accepted
    Time:30 ms
    Memory:21816 kb
****************************************************************/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值