题目描述
田忌赛马问题,田忌和王都有n匹马。n场比赛(每匹马都只能上场一次)。每场比赛输的要给赢的人200块钱,问最后田忌最多能获得多少钱。
输入n,接着是n匹田忌马速度,接着是n匹王的马速度,遇0结束。
样例
输入
3
92 83 71
95 87 74
2
20 20
20 20
2
20 19
22 18
0
输出
200
0
0
思路:显然为贪心问题。先要将田忌和王的马排序,从最慢的两匹马下手考虑。
A.若两匹最慢的马中田忌的马慢,不难知道田忌这匹马是所有马中最慢的。那不妨破罐破摔,那它去和王最快的马比,给队友多一点机会。
B.若两匹最慢的马中田忌的马快,那也不难知道田忌所有的马都比王这匹马快。那肯定是让最弱的马去比它,保留实力。
C.Here comes the question…………两匹最慢的马一样快怎么办?让他们打平?让田忌的最慢的马去消耗王最快的马?
很遗憾,都不是。在田忌1 2 王1 3这组数据下,显然不能简单让他们打平(-200)。这样不如去消耗王最快的马(0)。
而在田忌1 3 王 1 2 这组数据下,又不能简单去消耗王最快的马(0)这样不如让他们打平(200)。
那么看来,我们需要分类讨论。
a.田忌的快马比王的快马快。那么不难看出田忌的快马是所有马中最快的,那么肯定要让他赢王最快的马,给队友赢得机会。
b.田忌的快马比王的快马慢。那么王的快马是所有马中最快的。既然田忌的马没有比它快的,不妨让最慢的去消耗它,给队友赢得机会。
c.田忌的快马和王的快马一样快时,这时最慢的马和最快的马两人都一样快。这里我们选择让田忌的慢马去消耗王的快马。因为这样可以为队友留下最多的机会。虽然输了一场,但是至少可以让剩下的队友多赢一场(仔细理解)。
不难看出,以上的算法是贪心的。
另外,我觉得值得回味的是用了模拟指针。下面放代码。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int tian[1000],king[1000];
int main()
{
int n;
while(scanf("%d",&n) && n){
int cnt = 0;//记录田忌的胜负结果
memset(tian,0,sizeof(tian));
memset(king,0,sizeof(king));
for(int i = 0 ; i < n ; i ++) scanf("%d",&tian[i]);
for(int i = 0 ; i < n ; i ++) scanf("%d",&king[i]);
sort(tian,tian+n);
sort(king,king+n);
int pt1 = 0 , pt2 = n-1, pk1 = 0, pk2 = n-1;//模拟指针
while(pt1 < pt2 && pk1 < pk2){
if(tian[pt1] < king[pk1]){//A情况 田忌慢马<王慢马
pt1++;
pk2--;
cnt--;
}else if(tian[pt1] > king[pk1]){//B情况 田忌慢马>王慢马
pt1++;
pk1++;
cnt++;
}else{//C情况 田忌慢马=王慢马
if(tian[pt2] > king[pk2]){//C.a情况
pt2--;
pk2--;
cnt++;
}else if(tian[pt2] < king[pk2]){//C.b情况
pt1++;
pk2--;
cnt--;
}else{ //C.c情况 最快和最慢的马都相等
if(tian[pt1] == tian[pt2]){
break;//如果这时发现田忌的所有马速度都一样,那么就不要比了,因为下面都是平局
}else{
pt1++;
pk2--;
cnt--;
}
}
}
}
if(tian[pt1] < king[pk1]) cnt--;//最后还留下了一对马,比一下吧
if(tian[pt1] > king[pk1]) cnt++;
printf("%d\n",cnt*200);
}
return 0;
}
本文探讨了经典的田忌赛马问题,通过贪心算法来确定最佳的比赛策略,以最大化田忌的收益。文章详细解释了如何通过排序和比较双方马匹的速度来决定比赛配对,并提供了具体的代码实现。
745

被折叠的 条评论
为什么被折叠?



