解题思路:0/1背包
把实数转成整数,背包只适用整数,*100即可
可以报销的票,要么选,要么不选,且只能选一次。
不可报销的票:票价>1000,A、B、C类单项>600,注意,一张票可能A类出现不止一次。
0/1背包关键代码:
for (int i=1; i<=n; ++i) for (int j=V; j>=a[i]; --j)
d[j] = max(d[j], d[j-a[i]]+a[i]);
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define clr(p,v) memset(p,v,sizeof(p))
const int maxn = 33 ;
int n, ans, m, total;
int d[maxn], f[3000010];
int main()
{
double ff;
while (~scanf("%lf%d", &ff, &n))
{
if (!n) break;
total = ff * 100;
clr(d, 0);
m = 0;
while (n--)
{
int num, ta, tb, tc, tt;
bool fg;
fg = true;
d[m] = ta = tb = tc = tt = 0;
scanf("%d", &num);
while (num--)
{
char cc;
scanf(" %c:%lf", &cc, &ff);
int x = ff * 100;
tt += x;
if (cc == 'A') ta += x;
else if (cc == 'B') tb += x;
else if (cc == 'C') tc += x;
else fg = false;
}
if (fg && tt<=100000 && ta<=60000 && tb<=60000 && tc<=60000)
d[m++] = tt;
}
//
clr(f, 0);
if (total > 3000000) total = 3000000;
for(int i=0;i<m;++i)
{
for(int j=total; j>=d[i]; --j)
f[j] = max(f[j], f[j-d[i]]+d[i]);
}
//
printf("%.2lf\n", f[total]/100.0);
}
return 0;
}