洛谷::P2672
OJ:P4949
方法一:暴力搜索(40分)
解题策略:
为了在不走多余路的前提下最大化疲劳值,阿明应选择最远的住户 j
作为终点,并在返回的路上尽可能多地推销给距离较近且疲劳值高的住户。
在到达最远的住户 j
的过程中,他只能访问 j
之前的住户,因此需要从这些住户中选择 (X - 1)
个疲劳值最大的住户进行推销。
总疲劳值由以下三部分组成:
j
的往返距离产生的疲劳值:2 * a[j]
。j
处推销产生的疲劳值:b[j]
。(X - 1)
个住户产生的疲劳值:从 c[]
中选取的 (X - 1)
个最大 b[k]
值的总和。通过枚举所有可能的最远住户 j
,并对每种情况计算最大疲劳值,最终选取最大的疲劳值作为结果。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /**************************************************************** * Description: 2015年普及组复赛第四题 推销员 40分 * Author: Alex Li * Date: 2023-10-31 11:40:18 * LastEditTime: 2024-09-19 10:54:05 ****************************************************************/ #include <iostream> #include <algorithm> using namespace std; int n; int a[100005], b[100005], c[100005]; int main() { cin >> n; // 输入住户数量 // 读取每个住户到入口的距离 a[i] for (int i = 0; i < n; i++) cin >> a[i]; // 读取每个住户对应的推销疲劳值 b[i] for (int i = 0; i < n; i++) cin >> b[i]; // 对于不同的 X(要推销的住户数量) for (int X = 1; X <= n; X++) { int sum = 0; // 用于存储当前 X 下的最大疲劳值 // 尝试所有可能的最远访问的住户 j(从 X-1 开始,保证有足够的住户数量) for (int j = X - 1; j < n; j++) { int maxn = 0; // 当前方案的疲劳值 // 将从入口到第 j-1 个住户的疲劳值复制到数组 c 中 for (int k = 0; k < j; k++) c[k] = b[k]; // 对数组 c 进行排序,以便选择最大的 (X - 1) 个疲劳值 sort(c, c + j); // 选取最大的 (X - 1) 个疲劳值,累加到 maxn 中 for (int k = j - 1; k >= j - X + 1; k--) if (k >= 0) maxn += c[k]; // 加上到第 j 个住户的来回距离所产生的疲劳值和推销疲劳值 maxn += 2 * a[j] + b[j]; // 更新当前 X 下的最大疲劳值 sum = max(sum, maxn); } // 输出对于当前 X 的最大疲劳值 cout << sum << endl; } } |
方法二:100分
解题策略:从下面两种方案中选最大的
i
个疲劳值最大的住户,可能这些住户的距离并不远,但累积的疲劳值高。
pre[i]
。preMax[i]
。i - 1
个疲劳值最大的住户,再从剩余住户中选择一个 距离+疲劳值(2 * d + v)
最大的住户。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /**************************************************************** * Description: 2015年普及组复赛第4题,推销员 解法二 * Author: Alex Li * Date: 2023-11-01 10:41:55 * LastEditTime: 2024-09-19 11:50:04 ****************************************************************/ #include <iostream> #include <algorithm> // 引入算法库,用于 sort 函数 using namespace std; struct node { int d; // 距离 (distance to the entrance) int v; // 疲劳值 (fatigue value from selling to this household) } a[100005]; int pre[100005]; // 前缀和数组,表示按疲劳值排序后,前 i 个疲劳值之和 int last[100005]; // 后缀最大值数组,表示从第 i 个到第 n 个中,2*d + v 的最大值 int preMax[100005]; // 前缀最大值数组,表示前 i 个中,2*d 的最大值(即最大往返距离) int n; // 住户数量 // 比较函数,用于按疲劳值从大到小排序 bool cmp(node x, node y) { return x.v > y.v; } int main() { cin >> n; // 输入住户数量 // 读取每个住户到入口的距离 for (int i = 1; i <= n; i++) cin >> a[i].d; // 读取向每个住户推销产品所积累的疲劳值 for (int i = 1; i <= n; i++) cin >> a[i].v; // 按疲劳值从大到小排序 sort(a + 1, a + 1 + n, cmp); // 计算前缀和 pre[i],表示前 i 个最大的疲劳值之和 for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + a[i].v; // 计算 preMax[i],表示前 i 个中,2*d 的最大值(最大往返距离) for (int i = 1; i <= n; i++) preMax[i] = max(preMax[i - 1], 2 * a[i].d); // 计算 last[i],表示从第 i 个到第 n 个中,2*d + v 的最大值 // 这是为了考虑可能选择一个更远的住户,其往返距离和疲劳值的总和更大 for (int i = n; i >= 1; i--) last[i] = max(last[i + 1], 2 * a[i].d + a[i].v); // 对于每个 X(从 1 到 n),计算阿明能够积累的最大疲劳值 for (int i = 1; i <= n; i++) // 两种方案取最大值输出 // 方案一:选择前 i 个最大的疲劳值住户,往返距离为其中最大的 2*d // 总疲劳值为:pre[i] + preMax[i] // 方案二:选择前 i-1 个最大的疲劳值住户,另选一个剩余住户,使 2*d + v 最大 // 总疲劳值为:pre[i - 1] + last[i] cout << max(pre[i] + preMax[i], pre[i - 1] + last[i]) << endl; } |