田忌赛马
思路
拿到这道题,第一反应是什么?三匹马对三匹马,田忌可以自由安排出场顺序,问能不能赢至少两局。
那田忌的马一共有多少种出场顺序?3 匹马的全排列,也就是 种。数量这么少,直接暴力枚举所有排列不就行了?
具体做法
- 读入齐威王的三匹马速度(顺序固定),以及田忌的三匹马速度
- 对田忌的马生成所有排列(一共 6 种)
- 对每种排列,逐局比较:田忌的马速度严格大于齐威王的马才算赢
- 只要存在某种排列能赢 2 局及以上,输出
Yes;否则输出No
这题的关键点就一个:严格大于才算赢,等于不算。比如样例 2 里田忌有一匹速度为 3 的马,但另外两匹都是 2,和齐威王的 2 打平,赢不了两局。
代码
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int a[3], b[3];
for (int i = 0; i < 3; i++) cin >> a[i];
for (int i = 0; i < 3; i++) cin >> b[i];
// 枚举田忌马匹的所有排列
sort(b, b + 3);
do {
int win = 0;
for (int i = 0; i < 3; i++) {
if (b[i] > a[i]) win++; // 严格大于才赢
}
if (win >= 2) {
cout << "Yes" << endl;
return 0;
}
} while (next_permutation(b, b + 3));
cout << "No" << endl;
return 0;
}
import java.util.Scanner;
public class Main {
static int[] a = new int[3], b = new int[3];
static boolean found = false;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 3; i++) a[i] = sc.nextInt();
for (int i = 0; i < 3; i++) b[i] = sc.nextInt();
// 枚举田忌马匹的所有排列
permute(0);
System.out.println(found ? "Yes" : "No");
}
static void permute(int idx) {
if (found) return;
if (idx == 3) {
int win = 0;
for (int i = 0; i < 3; i++) {
if (b[i] > a[i]) win++; // 严格大于才赢
}
if (win >= 2) found = true;
return;
}
for (int i = idx; i < 3; i++) {
// 交换生成排列
int tmp = b[idx]; b[idx] = b[i]; b[i] = tmp;
permute(idx + 1);
tmp = b[idx]; b[idx] = b[i]; b[i] = tmp;
}
}
}
from itertools import permutations
a = list(map(int, input().split()))
b = list(map(int, input().split()))
for perm in permutations(b):
win = sum(1 for i in range(3) if perm[i] > a[i])
if win >= 2:
print("Yes")
exit()
print("No")
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line));
rl.on('close', () => {
const a = lines[0].split(' ').map(Number);
const b = lines[1].split(' ').map(Number);
function permute(arr) {
if (arr.length <= 1) return [arr];
const result = [];
for (let i = 0; i < arr.length; i++) {
const rest = arr.slice(0, i).concat(arr.slice(i + 1));
for (const perm of permute(rest)) {
result.push([arr[i], ...perm]);
}
}
return result;
}
for (const perm of permute(b)) {
let win = 0;
for (let i = 0; i < 3; i++) {
if (perm[i] > a[i]) win++;
}
if (win >= 2) {
console.log("Yes");
return;
}
}
console.log("No");
});
复杂度分析
- 时间复杂度:
,固定 3 匹马,最多枚举 6 种排列,每种比较 3 次
- 空间复杂度:
,只用了固定大小的数组
总结
这题就是个纯暴力枚举题,3 匹马的全排列才 6 种,没什么花活可玩。C++ 里 next_permutation 用起来很方便,记得先 sort 一下保证从最小排列开始。Java 没有现成的全排列函数,手写一个递归交换就好了。唯一要注意的就是"严格大于"这个条件,等于不算赢。



京公网安备 11010502036488号