机试题——填坑问题

题目描述

这是一条被动震损坏的路,路上出现了 N 个土坑,坑深度为 M。为了方便救灾,需要快速修复。由于填坑土方 K 是有限的,无法保证所有土坑百分百填满,需要确定最佳的填坑方案。

  • 车损简化计算公式:车损 = SUM(第 x 坑的未填深度 y)。
  • 坑越多,未填深度越多,则造成车损越严重。车损存在累计效应:同样深度的坑,第二个坑比第一个坑造成的车损更严重。

例如:共有 5 个坑,实施填坑之后,第 4 个坑仍有 2 单位深度未填,第 5 个坑仍有 1 单位深度未填,则车损 = 1^2 + 2^1 = 4。

  • 在土方数量有限的情况下,尽量填满土坑,最小化车损。
  • 若车损最小的情况下存在多个方案,则选择填得更多的坑,即选择填坑成本更低的方案。

输入描述

  • 第一行:一个整数 K,表示可用的土方量。
  • 第二行:一个由逗号分隔的整数序列,表示每个坑的深度。

输出描述

  • 输出一个由逗号分隔的整数序列,表示每个坑填充的土方数量。

示例输入

10
2,3,5,4,1
2,3,0,4,1
22
5,6,5,6,5,6
5,6,5,0,5,1

解题思路

  1. 回溯算法(DFS):使用深度优先搜索来遍历所有可能的填坑方案。每次尝试填不同量的土方,并计算当前方案的车损。

  2. 车损的计算

    • 对每个坑,车损是该坑未填的深度乘以该坑的编号(即该坑的顺序)。
    • 需要递归地尝试每个坑填不同的土方量,并计算车损的变化。
  3. 递归终止条件

    • 如果已经处理完所有坑,检查当前车损是否最小。如果最小,更新最优方案。
  4. 优化选择

    • 如果存在多个方案具有相同车损,选择填得更多的坑。

剪枝优化:先把土方按照顺序填完(对应每次i都为depths[idx],这样可以得到一个中间态的loss),在回溯中同时实时计算loss,车损大于最小车损时停止递归。

注意:n=100可能仍然无法通过全部样例,要完全通过样例需要改为dp。但是dp需要实时记录状态的填坑数量,土方数量等,较为麻烦

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;
vector<int> depths;  // 坑的深度
vector<int> result;// 实际答案
vector<int> temp;// 回溯
int min_loss = INT_MAX;//全局最小loss
int min_unfill = INT_MAX; //全局最小剩余的坑

// idx下标 rk剩余土方 p 前面有几个坑没填完 当前的loss  unfill 前面完全没填的数量
void dfs(int idx, int rk, int p, int loss,int unfill) {
    if (loss > min_loss) return;
    if (idx == depths.size()) {
        if (loss < min_loss||(loss == min_loss&& unfill <min_unfill)) {
            // 损伤小 或者损失一致 但是剩余的没填的坑少
            min_loss = loss;
            min_unfill = unfill;
            result = temp;
        }
        return;
    }
    for (int i = min(depths[idx], rk); i > 0; i--) {
        temp[idx] = i;
        if (i != depths[idx])
            dfs(idx + 1, rk - i, p + 1, loss + (p + 1) * (depths[idx] - i),unfill);
        else 
            dfs(idx + 1, rk - i, p, loss, unfill);
    }
    temp[idx] = 0;
    dfs(idx + 1, rk, p + 1, loss + (p + 1) * depths[idx], unfill + 1);
}

int main() {
    int k;  // 可用土方
    cin >> k;

    string line;
    cin.ignore();  // 忽略前面的换行符
    getline(cin, line);

    // 解析坑深度
    size_t pos = 0;
    while ((pos = line.find(',')) != string::npos) {
        depths.push_back(stoi(line.substr(0, pos)));
        line.erase(0, pos + 1);
    }
    depths.push_back(stoi(line));  // 添加最后一个数字
    int n = depths.size();
    /*
    for (int i = 0; i < depths.size(); i++) {
        cout << depths[i] << " ";
    }
    cout << endl;
    */
    result = vector<int>(n);
    temp = vector<int>(n);

    dfs(0, k, 0, 0,0);
    for (int i = 0; i < n; i++) {
        cout << result[i];
        if (i < n - 1) cout << ",";
    }
    cout << endl;
}

你可能感兴趣的:(#,hw机试题,算法,深度优先)