http://acm.hdu.edu.cn/showproblem.php?pid=1864
这里有让人犯迷糊的地方,可能是题意不清楚。当满足下面条件之一的,这张发票就不能报销,相当于作废:
1.一张发票上有除了 'A' 'B' C"之外还有别的类型的消费
2.这张发票的总总消费大于1000
3.单项物品的价值超过600
这样就变成了01背包问题。即某张发票被报销和不被报销两种情况。
还有就是给定的总额和发票的消费总额都是两位小数,可以先给他们同时扩大100倍,最后输出的时候再缩小100倍。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int maxn = 3000010; int dp[maxn]; int chk(char ch) { if(ch == 'A' || ch == 'B' || ch == 'C') return 1; return 0; } int main() { double Q; int n,m,v; int a[40]; while(~scanf("%lf %d",&Q,&n)) { if(n == 0) break; v = Q*100; //指定报销额扩大100倍 for(int i = 1; i <= n; i++) { scanf("%d",&m); double A = 0,B = 0,C = 0,x,s = 0; int f = 1; char str; while(m--) { scanf(" %c:%lf",&str,&x); if(chk(str) == 0) f = 0; if(str == 'A') A += x; if(str == 'B') B += x; if(str == 'C') C += x; s += x; } if(A > 600 || B > 600 || C > 600 || s > 1000 || f == 0) a[i] = 0; //该发票不符合要求,置为0. else a[i] = s*100;//否则发票的总价值也扩大100倍 } memset(dp,0,sizeof(dp)); dp[0] = 1; //初始化。0肯定能达到 int ans = 0; for(int i = 1; i <= n; i++) { for(int j = v; j >= a[i]; j--) { if(dp[j-a[i]]) { dp[j] = 1; ans = max(ans,j); } } } printf("%.2lf\n",ans/100.0); //最后还原 } return 0; }