题目
思路
这个题主的难点要有三个方面。
第一个方面是数据不好输入。题目中所给的数据都是做题需要的数据,而且是需要分开存储的。对于字母:数字的格式输入,我们可以采用scanf的格式化输入来完成,从而实现,字母、数字分开操作;
第二个方面就是01背包的问题,这个题目给出的数据全是小数,而01背包的一维数组类型需要对背包内存Q进行逆序循环,从而要求是整数,由于题中所给出的小数都是两位数的,所以我们可以将它们×100再进行运算;
第三个方面是01背包问题中一维数组创立的问题,显然这个一维数组是不能用容器vector来代替的(想想为什么?),而题中所给的Q×100后可以会达到十万级别,但是有时的Q不排除较小的情况,这样一来,我们对于一维数组申请内存就不太好操作,过大可能会超出限度,过小会导致越界。因此我们需要用new与delete来动态分配内存。
AC代码1
#include <bits/stdc++.h>
using namespace std;
char type;
double d_price, d_Q;
int n, num;
string s;
vector<int> v;
int main() {
while (true) {
v.clear();
cin >> d_Q >> num;//Q是允许的报销额 num是发票张数
if (num == 0)
return 0;//等于0就直接退出
for (int j = 1; j <= num; ++j) {//有几张发票 一张一张的计算
int sum = 0;
cin >> n; //发票上的物件儿数
for (int i = 1; i <= n; ++i) {
scanf(" %c:%lf", &type, &d_price);
int price = d_price * 100;//转为整数
if ((type == 'A' || type == 'B' || type == 'C') && price <= 60000) {
//满足四种条件才能相加
sum += price;
} else {
sum = 0;
getline(cin, s); //如果有不符合的后面的数据直接当作字符串输入不使用
break;//然后直接用下一张发票
}
}
if (sum != 0 && sum <= 100000)
v.push_back(sum);
}
int len = v.size(), Q = d_Q * 100; //v是存放对应金额的容器
int *dp;
dp = new int[Q + 1];//可以用变量来声明大小
for (int i = 0; i <= Q; ++i) {
dp[i] = 0;
}
for (int i = 0; i < len; ++i) {
for (int j = Q; j >= 1; --j) {
if (v[i] <= j) { //可以放进去
dp[j] = max(dp[j], dp[j - v[i]] + v[i]);;
}
}
}
printf("%.2lf\n", dp[Q] / 100.0);
delete[] dp;//释放一组内存
}
}
AC代码2
//最大报销额
#include <bits/stdc++.h>
using namespace std;
int arr[50];
int main() {
double Q, price;
int N, d_price;
char c;//代表发票的种类
while (cin >> Q >> N, N != 0) {
int max_ = 0;
int len = 1;
memset(arr, 0, sizeof(arr));
int d_Q = Q * 100; //0 1背包问题要遍历Q
for (int s = 0; s < N; ++s) {
int sum = 0;
int num;//这是每张发票里面的物品数
cin >> num;
for (int j = 0; j < num; ++j) {
scanf(" %c:%lf", &c, &price);
//cout << c << " " << price << endl;
d_price = price * 100;
if ((c == 'A' || c == 'B' || c == 'C') && d_price <= 60000) {
sum += d_price;
} else {
sum = 0;
break;
}
}
if (sum != 0 && sum <= 100000)
arr[len++] = sum;
}
int *dp;
dp = new int [d_Q + 1];
//开始dp
for (int k = 0; k < d_Q; ++k) {
dp[k] = 0;
}
for (int i = 1; i <= len; ++i) {
for (int j = d_Q; j >= arr[i]; --j) {
dp[j] = max(dp[j], dp[j - arr[i]] + arr[i]);
max_ = max(max_, dp[j]);
}
}
printf("%.2lf\n", max_ / 100.0);
delete[] dp;
}
}
new与delete
C++使用了new与delete来操控内存的释放问题。比C语言的malloc/alloc/realloc和free更好用,可以对类对象调用初始化构造函数或者销毁析构函数。(在堆存储区,向操作系统申请内存)申请完内存后,要用delete还给操作系统,不能一直占据。
由于静态数组的大小只能是常量,不能是变量,在做一些题的时候并不是十分方便,所以我们会使用动态数组来定义符合自己需要长度的数组,这时的动态数组是支持变量来定义大小的。只是我们需要用指针来定义它,要手动来释放它、手动来初始化它内部的值。
但是在DevC++中,我们可以使用变量来声明一个静态数组,在vs code中却不行,也挺玄乎的喔~
所以还是好好地规范使用new与delete吧。