01揹包-03 小P的故事——神奇的發票報銷
阿新 • • 發佈:2018-12-23
小P的故事——神奇的發票報銷
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
為響應黨的號召,小P所在的大學現在嚴格規範報銷制度,禁止鋪張浪費。特作如下規定:允許報銷的發票型別包括買圖書(A類)、文具(B類)、差旅(C類),要求每張發票的總額不得超過1000元,每張發票上,單項物品的價值不得超過600元。
現在老師決定把這報銷發票的重任交付於小P,給他一沓發票,讓他找出可以報銷的、不超過給定額度的最大報銷額。小P能成功完成組織交給他的任務嗎?顯然不能啊、、所以還得靠你啊、、、
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
Hint
Source
xfl
#include <bits/stdc++.h> using namespace std; int dp[3000001], vi[33]; int main() { double q, num, A, B, C; int n; char c; while (~scanf("%lf %d", &q, &n) && n) { int Q = q * 100; // 避免dp陣列出問題我們把錢數都乘100 memset(dp, 0, sizeof(dp)); memset(vi, 0, sizeof(vi)); for (int m = 0; m < n; m++) { int sum, k, flag = 1; sum = A = B = C = 0; scanf("%d", &k); getchar(); // 收納行末回車 for (int i = 0; i < k; i++) { scanf("%c:%lf", &c, &num); getchar(); if (c == 'A') A += num * 100; else if (c == 'B') B += num * 100; else if (c == 'C') C += num * 100; else // 不是ABC的情況 flag = 0; } sum = A + B + C; if (A > 60000 || B > 60000 || C > 60000) flag = 0; if (sum <= 100000 && flag) // 當小於報銷金額且 沒有600的沒有不是ABC的時候 vi[m] = sum; else vi[m] = 0; } /*01揹包部分*/ for (int i = 0; i < n; i++) { for (int j = Q; j > 0; j--) { if (j >= vi[i]) dp[j] = max(dp[j], dp[j - vi[i]] + vi[i]); } } printf("%.2lf\n", dp[Q] / 100.0); } return 0; }