Problem P31. [算法课分支限界法]大礼包
采用了回溯的方法。先选用第一个大礼包,然后一直到选第一个大礼包 n 次。其中递归调用自身决定下一个大礼包选用几次。
题目难点:
- 回溯的时候比较麻烦,因为可能遍历到中间才知道,哦,这个大礼包不能用,这时候就要把数组恢复到一开始的状态,详细做法可以看代码
- 多行输入,采用的方法可见代码,这是多行不定长输入的方法。
#include<iostream>
#include<bits/stdc++.h>
#include<cstdio>
#include<string>
using namespace std;
int cost = -1;
void backtrack(vector<int>& price, vector<vector<int>>& special, vector<int>& needs, int idx, int sum) {
if (idx == special.size()) {
if (cost != -1) {
cost = min(cost, sum);
} else {
cost = sum;
}
return;
}
bool flag = true;
int k = 0;
backtrack(price, special, needs, idx+1, sum);
while (flag) {
int j = 0;
for (j = 0; j < needs.size(); j++) {
needs[j] -= special[idx][j];
if (needs[j] < 0) {
break;
}
sum -= special[idx][j]*price[j];
// cout << idx << " " << j << " " << sum << endl;
}
if (j == needs.size()) {
sum += special[idx][needs.size()];
backtrack(price, special, needs, idx+1, sum);
k++;
continue;
}
for (; j >= 0; j--) {
needs[j] += special[idx][j];
}
flag = false;
}
for (int j = 0; j < needs.size(); j++) {
needs[j] += k*special[idx][j];
}
}
int main()
{
vector<int> price, needs;
vector<vector<int>> special;
int d;
while (cin >> d) {
price.push_back(d);
if (getchar() == '\n') {
break;
}
}
int n = price.back();
price.pop_back();
for (int i = 0; i < n; i++) {
vector<int> arr;
while (cin >> d) {
arr.push_back(d);
if (getchar() == '\n') {
break;
}
}
special.emplace_back(arr);
}
while (cin >> d) {
needs.push_back(d);
if (getchar() == '\n') {
break;
}
}
int sum = 0;
for (int i = 0; i < price.size(); i++) {
sum += price[i]*needs[i];
}
backtrack(price, special, needs, 0, sum);
cout << cost << endl;
return 0;
}
总算写完学校的34道题了,写随笔写到一半就不想写了,但是感觉这样不好,这样之前的随笔就变得不完整了。终于写完了,之后每天好好刷力扣。