题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1052
题目大意:
给你田忌和国王的马匹每匹所代表的值,值越高代表这个马越厉害。然后输出这种情况下的,田忌最多能赢多少银两。赢一场可以得200银两【注:可以为负值。比如输了三局,就是-600】
题目思路:
贪心算法,在这就是分类讨论思想:
我们记田忌最快的马为QT,最慢的马为ST
记国王最快的马为QK,最慢的马为SK
那么可以分为以下情况:
1)ST>SK,就直接比,算赢一场
2)ST<SK,就让田忌的最慢的马与王最快的马相比,算输一场
3)ST==SK,我们需要再往下讨论如下:
*******3.1):QT>QK,直接比,记赢一场
*******3.2):QT<=QK,需要判断一下,
*****************3.2.1):如果ST<QK【注意:这里不是打错了,就是要判断田忌最慢的马是否小于王最快的马,因为要保证田忌每次输都应该是用最差的换掉王最好的】,就记输一次,用田忌最差的马换掉王最好的马。
*****************3.2.2):如果QT=QK,其实就相当于是场上所剩下的所有的马值都是一样的。
因为我们这个情况是在ST==SK和QT<=QK条件下的,如果QK==ST,那么只有一种情况就是ST==SK==QK==QT。但是!!!!我们不能直接将其return 0 掉,因为ST、SK、QK、QT这四个是动态变化的有可能是最后中间出现了这种相等的情况,如果直接return0的话,之前找的就相当于是白找了,看下面的例子
所以满足这种"3.2.2"的情况的可能有:
3
77 77 77
77 77 77
如果单单只是上面这种一开始就进入这个情况,我们确实可以直接return 0掉然而,也有可能是以下的情况:
4
76 77 77 77
77 77 77 78
这样子的话直接return0掉的话,就会导致答案错误,正确答案其实是-200,也就是说之前找的情况直接被覆盖了。
所以碰到这种情况我们处理方式就是,直接return win的值回来【注:win的值记录的是田忌累计的输赢情况】。这时候return win的值其实就相当于是将这只之前的输赢情况返回了,后面全是平局没有查找的必要了。
ac代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int Tian[1005];
int King[1005];
int n;//马匹数
int race(){
//sort第二个变量为数组的最后一个的再后一个位置
sort(Tian,Tian+n);//给马匹按照从小到大的顺序排序
sort(King,King+n);
int win = 0;
int Thead,Ttail;//记录田忌马的前后检测位置
int Khead,Ktail;//国王的
Thead = 0;
Khead = 0;
Ttail = n-1;
Ktail = n-1;
while(Thead<=Ttail){
if(Tian[Thead]>King[Khead]){//两匹最慢的马直接比
win++;
Thead++;
Khead++;
continue;
}
else if(Tian[Thead]<King[Khead]){//田忌的马与王最快的马比
win--;
Thead++;
Ktail--;
continue;
}else{//当两个最慢的马相等时
if(Tian[Ttail]>King[Ktail]){//两匹快马直接比
win++;
Ttail--;
Ktail--;
}
else{//田忌的快马不如王的快马快时
if(King[Ktail]>Tian[Thead]){//当王的快马快于田忌的慢马时
//算田忌输一局
win--;
Thead++;
Ktail--;
}else{//因为在这之后全是相等的了,也就是平局,可以直接返回值了
return win;
}
}
}
}
return win;
}
int main(){
int ans;
while(cin>>n){
if(n==0){
break;
}
for(int i = 0;i < n;i++){
cin>>Tian[i];
}
for(int j = 0;j < n;j++){
cin>>King[j];
}
ans = race();
cout<<ans*200<<endl;
}
return 0;
}