0
点赞
收藏
分享

微信扫一扫

简单贪心(二)田忌赛马问题

写在前面:

田忌赛马并不只是贪心算法的专属,同样设计到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写。

贪心是田忌赛马的一个推荐解法,找对贪心策略便很容易。

举报

相关推荐

0 条评论