题目:
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*/ 
                


















