1864年最大の償還HDU 0-1バックパック
問題の意味
お金の既存の合計は、請求書の一定額を弁償することができます。請求書の種類は、本を購入することができ償還(タイプ)、文具(クラスB)、総旅行(Cタイプ)は、すべての請求書、ない以上$ 600の個々の項目の値は、各請求書が1000を超えてはならない必要が含ま。今、あなたは、特定の償還の請求書の山を見つけるための最大の償還クォータ度を超えないようにプログラムを書きます。
ここでは、それが返済することができない限り、合計金額が1000を超える、または600より大きいの各カテゴリ、または請求書の合計金額であるとして、商品の他のカテゴリがあり、それを注意する必要があります
問題解決のためのアイデア
これは簡単である\(0-1 \)バックパック、主態様は、データの前処理です。
もう一つのポイントは、配列の添字整数が必要ですが、この量は、浮動小数点され、どのようにそれを行うには?私たちは、ここで入力したデータが2つの小数点以下の桁数を保持していることがわかったので、私たちすることができますそれぞれの量\(* 100 \) 、我々は整数がすべてですので。
いくつかの詳細は、コードを参照してください。
コードの実装
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=40;
const int maxm=4e5+7;
const int maxq=1000*30*100+7;
double rec[maxn];
double dp[maxq];
double q;
int n, m;
int main()
{
while(scanf("%lf%d", &q, &n) && n!=0)
{
char type;
int flag, cnt=0; //使用cnt来记录实际合法的发票个数
while(n--)
{
double price, va=0, vb=0, vc=0;//总金额,A,B,C类的总金额
flag=1; //一个标记
scanf("%d", &m);
while(m--)
{
scanf(" %c:%lf", &type, &price);
if(flag==0)//如果标记为0的话,说明前面有不合法的数据,这个发票也就作废了
continue;
if(type=='A')
va+=price;
else if(type=='B')
vb+=price;
else if(type=='C')
vc+=price;
else flag=0;
}
//下面会再次进行判断
if(flag==1 && va<=600.0 && vb<=600.0 && vc<=600.0 && (va+vb+vc)<=1000.0)
{
rec[++cnt]=va+vb+vc;
}
}
memset(dp, 0, sizeof(dp));
int max_val=int(q*100);//最大金额化成整数
for(int i=1; i<=cnt; i++)
{
for(int j=max_val; j>=int(rec[i]*100); j--) //每张发票的金额也要化成整数
{
dp[j]=max(dp[j-int(rec[i]*100)]+rec[i], dp[j]);
}
}
printf("%.2lf\n", dp[max_val]);//注意输出格式,要求小数点后两位。
}
return 0;
}