现有 n 根木棒,已知它们的长度和重量,要用一部木工机一根一根地加工这些木棒。该机器在加工过 程中需要一定的准备时间,是用于清洗机器、调整工具和模板的。木工机需要的准备时间如下: (1)第一根木棒需要 1 分钟的准备时间。 ( 2 ) 在加工完一根长为 length 、重为 weight 的木棒之后,接着加工一根长为 length`(length<=length`),重为 weight`(weight<=weight`)的木棒是不需要任何准备时间的。否则需要 1 分钟的准备时间。 本题要求是: 给定 n(1≤n≤5000)根木棒,已知它们的长度和重量,请编写程序:找到加工完所有的木棒所需的最 少准备时间,以及加工这些木棒的顺序。
时间: 2024-02-15 12:03:14 浏览: 154
这个问题可以使用动态规划来解决。我们可以将问题分为两个子问题:选择当前木棒和不选择当前木棒。我们设$dp[i]$表示加工前$i$根木棒所需的最少准备时间,$pre[i]$表示在加工第$i$根木棒之前,加工的最后一根木棒的编号。则状态转移方程为:
$$
dp[i] = \begin{cases}
1 + dp[i-1] & (i=1) \\
\min_{j<i, length_j \leq length_i, weight_j \leq weight_i} \{dp[j]\} + 1 & (i>1)
\end{cases}
$$
其中,$1+dp[i-1]$表示选择当前木棒,$j<i$表示不选择当前木棒,$length_j \leq length_i, weight_j \leq weight_i$表示满足条件的前一根木棒。根据上述方程,我们可以使用动态规划求解出$dp[n]$,然后通过$pre$数组逆推出加工的顺序。
下面是用C++实现的代码:
```c++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 5005;
struct Stick {
int length, weight, id;
bool operator<(const Stick &rhs) const {
if (length != rhs.length) {
return length < rhs.length;
}
return weight < rhs.weight;
}
};
int n;
Stick sticks[MAXN];
int dp[MAXN], pre[MAXN];
void print(int i) {
if (i == 0) {
return;
}
print(pre[i]);
cout << sticks[i].id << endl;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> sticks[i].length >> sticks[i].weight;
sticks[i].id = i;
}
sort(sticks + 1, sticks + n + 1);
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + 1;
pre[i] = i-1;
for (int j = i-1; j >= 1; j--) {
if (sticks[j].length <= sticks[i].length && sticks[j].weight <= sticks[i].weight) {
if (dp[j] + 1 < dp[i]) {
dp[i] = dp[j] + 1;
pre[i] = j;
}
}
}
}
cout << dp[n] << endl;
print(n);
return 0;
}
```
该代码的时间复杂度为$O(n^2)$,可以通过本题。
阅读全文