[GESP202312 四级] 田忌赛马
题目描述
你要和田忌赛马。你们各自有 N N N 匹马,并且要进行 N N N 轮比赛,每轮比赛,你们都要各派出一匹马决出胜负。
你的马匹的速度分别为 u 1 , u 2 , ⋯ , u n u_1,u_2,\cdots,u_n u1,u2,⋯,un,田忌的马匹的速度分别为 v 1 , v 2 , ⋯ , v n v_1,v_2,\cdots,v_n v1,v2,⋯,vn。田忌会按顺序派出他的马匹,请问你要如何排兵布阵,才能赢得最多轮次的比赛?巧合的是,你和田忌的所有马匹的速度两两不同,因此不可能出现平局。
输入格式
第一行一个整数 N N N。保证 1 ≤ N ≤ 5 × 1 0 4 1\le N \le 5\times 10^4 1≤N≤5×104
接下来一行 N N N 个用空格隔开的整数,依次为 u 1 , u 2 , ⋯ , u n u_1,u_2,\cdots,u_n u1,u2,⋯,un,表示你的马匹们的速度。保证 1 ≤ u i ≤ 2 N 1\le u_i\le 2N 1≤ui≤2N。
接下来一行 N N N 个用空格隔开的整数,依次为 v 1 , v 2 , ⋯ , v n v_1,v_2,\cdots,v_n v1,v2,⋯,vn,表示田忌的马匹们的速度。保证 1 ≤ v i ≤ 2 N 1\le v_i\le 2N 1≤vi≤2N。
输出格式
输出一行,表示你最多能获胜几轮。
样例 #1
样例输入 #1
3
1 3 5
2 4 6
样例输出 #1
2
样例 #2
样例输入 #2
5
10 3 5 8 7
4 6 1 2 9
样例输出 #2
5
提示
样例解释 1
第 1 轮,田忌派出速度为 2 的马匹,你可以派出速度为 3 的马匹迎战,本轮你获胜。
第 2 轮,田忌派出速度为 4 的马匹,你可以派出速度为 5 的马匹迎战,本轮你获胜。
第 3 轮,田忌派出速度为 6 的马匹,你可以派出速度为 1 的马匹迎战,本轮田忌获胜。
如此,你可以赢得 2 轮比赛。
解析
题目描述:
你要和田忌赛马。你们各自有N匹马,并且要进行N轮比赛,每轮比赛,你们都要各派出一匹马决出胜负。你的马匹的速度分别为u1,u2,…,un,田忌的马匹的速度分别为v1,v2,…,vn。田忌会按顺序派出他的马匹,请问你要如何排兵布阵,才能赢得最多轮次的比赛?巧合的是,你和田忌的所有马匹的速度两两不同,因此不可能出现平局。
解题思路:
这是一个经典的贪心算法问题。我们可以按照以下策略来安排比赛:
- 将你的马匹按速度从小到大排序,将田忌的马匹按速度从小到大排序。
- 从速度最慢的马匹开始,每次选择你的马匹中速度最慢且能够战胜田忌当前马匹的马匹出战。
- 如果你没有马匹能够战胜田忌当前的马匹,则选择你最慢的马匹出战。
这种策略的思路是,尽可能用较慢的马匹去战胜田忌的马匹,从而节省更快的马匹来对付田忌的更快的马匹。
C++代码实现:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;int main() {int N;cin >> N;vector<int> u(N), v(N);for (int i = 0; i < N; ++i) {cin >> u[i];}for (int i = 0; i < N; ++i) {cin >> v[i];}sort(u.begin(), u.end());sort(v.begin(), v.end());int i = 0, j = 0, wins = 0;while (i < N && j < N) {if (u[i] > v[j]) {++wins;++j;}++i;}cout << wins << endl;return 0;
}
代码解释:
- 读入数据,包括马匹数量N,以及你的马匹速度向量u和田忌的马匹速度向量v。
- 使用
sort
函数对向量u和v分别进行排序。 - 定义指针i和j,分别指向向量u和v的起始位置,定义计数变量wins,初始值为0。
- 使用while循环,同时遍历向量u和v:
- 如果u[i] > v[j],说明你的当前最慢的马匹能够战胜田忌的当前马匹,将wins加1,并将j向后移动一位。
- 无论是否获胜,将i向后移动一位,表示你的当前马匹已经出战。
- 输出wins的值,即为你能够获胜的最多轮数。
这个解法的时间复杂度为O(NlogN),主要是排序的时间复杂度。空间复杂度为O(N),需要存储两个向量。
与之前的解法相比,这个解法使用了C++的STL向量(vector)和算法(algorithm)库,代码更加简洁易读。同时,在遍历向量时,使用了while循环和两个指针i和j,避免了不必要的比较和移动操作。