题目:
Problem D. 负重越野 您正在参加一场团体越野比赛。您的队伍共有 n 名队员,其中第 i 名队员的速度为 vi,体重为 wi。 比赛允许每名队员独立行动,也允许一名队员背着另一名队员一起行动。当队员 i 背着队员 j 时,如果 队员 i 的体重大于等于队员 j,则队员 i 的移动速度不会变化,仍然为 vi;如果队员 i 的体重小于队员 j,则队员 i 的移动速度会减去两者的体重差值,即变为 vi − (wj − wi)。如果队员 i 的移动速度将变为 负数,则队员 i 无法背起队员 j。每名队员最多只能背负另一名队员,被背负的队员无法同时背负其他 队员。 所有未被背负的队员中,最慢的队员的速度,即为整个队伍的速度。求整个队伍能达到的最大速度。 Input 有多组测试数据。第一行输入一个整数 T 表示测试数据组数,对于每组测试数据: 第一行输入一个整数 n(1 ≤ n ≤ 105)表示队员人数。 对于接下来 n 行,第 i 行输入两个整数 vi 和 wi(1 ≤ vi , wi ≤ 109)表示第 i 名队员的速度和体重。 保证所有数据中 n 之和不超过 105。 Output 每组数据输出一个整数,表示整个队伍可以达到的最大速度。
INPUT:
2 5 10 5 1 102 10 100 7 4 9 50 2 1 100 10 1
OUTPUT:
8 1
Note 样例数据的最优策略如下: • 队员 1 背起队员 4。因为 w1 > w4,因此队员 1 速度不变,仍然为 10。 • 队员 3 背起队员 2。因为 w3 < w2,因此队员 3 的速度减少 w2 −w3 = 2,即速度变为 10−2 = 8。 • 队员 5 独立行动,速度为 9。 因此答案为 8。
分析:
这个问题可以看作是一个贪心算法的问题,即每次选择能使整个队伍速度最大的方案。具体的思路如下:
- 首先,将所有队员按照速度从大到小排序,如果速度相同,则按照体重从小到大排序。这样可以保证在选择背负方案时,优先考虑速度快且体重轻的队员。
- 然后,从前往后遍历排序后的队员,对于每个队员 i,检查是否有另一个队员 j 满足以下条件:
- 队员 j 没有被背负过,也没有背负过其他队员。
- 队员 i 的体重大于等于队员 j 的体重,或者队员 i 的速度减去两者的体重差值仍然大于等于队员 j 的速度。
- 如果有多个满足条件的队员 j,则选择体重最大的那个。
- 如果找到了这样的队员 j,则让队员 i 背负队员 j,并更新队员 i 的速度为 min(vi, vi - (wj - wi))。否则,让队员 i 独立行动。
- 最后,遍历所有未被背负的队员,找出他们中速度最小的那个,即为整个队伍的速度。
//代码尚有错误,等待重改
:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct ss {
int v;
int w;
bool ced; // 是否被背负
bool cing; // 是否背负其他人
};
// 定义一个比较函数,按照速度降序,体重升序排序
bool cmp(ss a, ss b) {
if (a.v == b.v) {
return a.w < b.w;
}
return a.v > b.v;
}
// 定义一个函数,求解整个队伍能达到的最大速度
int solve(vector<ss>& ple) {
sort(ple.begin(), ple.end(), cmp);
for (int i = 0; i < ple.size(); i++) {
// 如果当前队员已经被背负过或者已经背负过其他人,则跳过
if (ple[i].ced || ple[i].cing) {
continue;
}
// 初始化最佳选择的下标和速度差值
int best = -1;
int diff = 0;
// 遍历剩余的队员
for (int j = i + 1; j < ple.size(); j++) {
// 如果当前队员已经被背负过或者已经背负过其他人,则跳过
if (ple[j].ced || ple[j].cing) {
continue;
}
// 计算两者的体重差值和速度差值
int wdiff = ple[j].w - ple[i].w;
int sdiff = ple[i].v - ple[j].v;
// 如果满足条件,则更新最佳选择和速度差值
if (wdiff <= 0 || sdiff >= wdiff) {
if (best == -1 || wdiff > diff) {
best = j;
diff = wdiff;
}
}
}
// 如果找到了最佳选择,则让队员 i 背负队员 j,并更新队员 i 的速度
if (best != -1)
{
ple[i].cing = true;
ple[best].ced = true;
ple[i].v = min(ple[i].v, ple[i].v - diff);
}
}
// 初始化整个队伍的速度为最大值
int team_v = INT_MAX;
// 遍历所有未被背负的队员,找出速度最小的那个
for (int i = 0; i < ple.size(); i++) {
if (!ple[i].ced) {
team_v = min(team_v, ple[i].v);
}
}
// 返回整个队伍的速度
return team_v;
}
int main() {
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ss> ple(n);
for (int i = 0; i < n; i++) {
cin >> ple[i].v >> ple[i].w;
ple[i].ced = false;
ple[i].cing = false;
}
cout << solve(ple) << endl;
}
return 0;
}
/*2
5
10 5
1 102
10 100
7 4
9 50
2
1 100
10 1*/