首先强调不超过600元的是一张发票上同一类商品的额度总和,而题意描述的是单项物品,坑!
输入有空格字符,需要注意一下。然后每一张发票输入完之后,判断是否满足报销条件,如果满足则存入w数组。
之后就是一个01背包问题了,只不过这里的价值和花费相等,只需要一个数组存下即可。不过利用dp数组进行状态转移的时候需要注意,因为最后的精度要求是小数点后两位,所以要遍历到每一种状态的话,要将整体的数据都扩大一百倍,否则当前状态没法用数组下标表示。最后将结果再缩小100倍即可。
代码如下(未精简,略冗长):
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
#define mem(a, i) memset(a, i, sizeof(a))
#define INF 0x3f3f3f3f
int dp[4999000];
int main()
{
//freopen("in.txt", "r", stdin);
int n;
double q;
while(cin >> q >> n && n)
{
int w[1010];
int m;
char s, c;
mem(w, 0);
for(int i = 1; i <= n; ++ i)
{
cin >> m;
bool flag = true;
double h, A = 0, B = 0, C = 0, sum = 0;
for(int j = 0; j < m; ++ j)
{
c = getchar();
s = getchar();
c = getchar();
if(!(s == 'A' || s == 'B' || s == 'C'))
{
flag = false;
}
cin >> h;
if(s == 'A')
{
A += h;
}
else if(s == 'B')
{
B += h;
}
else if(s == 'C')
{
C += h;
}
}
if(A > 600 || B > 600 || C > 600)
{
flag = false;
}
else
{
sum += (A + B + C);
}
if(flag && sum <= 1000)
{
w[i] = (sum * 100);
}
else
{
w[i] = INF;
}
}
mem(dp, 0);
int p = (q * 100);
for(int i = 1; i <= n; ++ i)
{
for(int j = q * 100; j >= 0; --j)
{
if(j < w[i])
{
dp[j] = dp[j];
}
else
{
dp[j] = max(dp[j - w[i]] + w[i], dp[j]);
}
}
}
printf("%.2lf\n", dp[p] * 1.0 / 100);
}
return 0;
}