写在前面:
田忌赛马并不只是贪心算法的专属,同样设计到DP(动态规划)、二分图的一些有趣知识,也许以后我会开一篇文章详细谈谈QwQ
题目链接:
田忌赛马 - 洛谷
题目描述
“田忌赛马”是中国历史上一个著名的故事。
大约2300年前,齐国大将田忌喜欢和国王赛马,并且约定:每赢一场,对方就要付200银币。
假设已知田忌和国王的各自马匹的速度都不相同,请计算田忌最好的结果是什么。
Input
第一行一个整数n,表示他们各有几匹马(两人拥有的马的数目相同)。第二行n个整数,每个整数都代表田忌的某匹马的速度值(0 <= 速度值<= 100)。第三行n个整数,描述齐王的马的速度值。两马相遇,根据速度值的大小就可以知道哪匹马会胜出。如果速度值相同,则和局,谁也不拿钱。
【数据规模】
对于20%的数据,1<=N<=65;
对于40%的数据,1<=N<=250;
对于100%的数据,1<=N<=2000。
Output
仅一行,一个整数,表示田忌最大能得到多少银币。
题目分析
这是一个弱者——田忌以弱胜强的经典故事,从故事本身中我们不难发现,田忌只有在有把握赢的情况下拿出快马与齐王比,否则就拿最慢的马来和齐王最快的马“同归于尽”,最大程度的削弱对手的战斗力。
就比如在篮球比赛中,如果你与对手实力相差悬殊,不妨让己方最差的球员去对标对方最好的球员,实现“极限一换一”。
OK,那我们来把这些闲言碎语整理成具体策略:
1. 如果田忌最快的马比齐王最快的马快,则两者比(如果不这样可能会输);
2. 如果田忌最快的马比齐王最快的马慢,则拿田忌最慢的马与齐王最快的马比(齐王拿出最快的马后,田忌怎么样都得输,不妨拿最慢的马比,让损失最小);
3. 如果田忌最快的马与齐王最快的马一样快,则比较双方最慢的马:
>>如果田忌最慢的马比齐王最慢的马快,则两者比
>>其他情况,拿田忌最慢的马与齐王最快的马比(这匹马无论如何都赢不了,不如与对方最 快的马“同归于尽”)
OK,这就是全部策略了,代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2121;
int a[maxn], b[maxn]; //懒了,a数组代表田忌一方,b数组代表齐王一方
int main(){
int n, sum, la, lb, ra, rb; //sum是最终赢钱数,l与r分别指向最差与最好的马
cin>>n;
for(int i = 0; i < n; ++i)
scanf("%d", &a[i]);
for(int i = 0; i < n; ++i)
scanf("%d", &b[i]);
sort(a, a+n), sort(b, b+n); //按从慢到快排序
sum = 0;
la = lb = 0;
ra = rb = n-1;
for(int i = 0; i < n; ++i){
if(a[ra] > b[rb]){
sum += 200;
ra--; rb--;
}else if(a[ra] < b[rb]){
sum -= 200;
la++; rb--;
}else if(a[la] > b[lb]){
sum += 200;
la++; lb++;
}else{
if(a[la] < b[rb]) //注意这一行代码,没有它会错
sum -= 200;
la++; rb--;
}
}
cout<<sum;
return 0;
}
注意:代码中的那行if是在避免这种情况,即最后大家都剩一匹马,最好的与最坏的马是同一匹,即ra = la, rb = lb, 满足a[ra] = b[rb]后进入else循环,但这种情况下不该输200元,因为是平局。当然也可以直接用else if写。
贪心是田忌赛马的一个推荐解法,找对贪心策略便很容易。