Problem P31. [算法课分支限界法]大礼包

采用了回溯的方法。先选用第一个大礼包,然后一直到选第一个大礼包 n 次。其中递归调用自身决定下一个大礼包选用几次。

题目难点:

  1. 回溯的时候比较麻烦,因为可能遍历到中间才知道,哦,这个大礼包不能用,这时候就要把数组恢复到一开始的状态,详细做法可以看代码
  2. 多行输入,采用的方法可见代码,这是多行不定长输入的方法。
#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道题了,写随笔写到一半就不想写了,但是感觉这样不好,这样之前的随笔就变得不完整了。终于写完了,之后每天好好刷力扣。

posted @ 2022-10-19 00:28  白缺  阅读(204)  评论(0编辑  收藏  举报