P1650 赛马
题目描述
我国历史上有个著名的故事: 那是在2300年以前。齐国的大将军田忌喜欢赛马。他经常和齐王赛马。他和齐王都有三匹马:常规马,上级马,超级马。一共赛三局,每局的胜者可以从负者这 里取得200银币。每匹马只能用一次。齐王的马好,同等级的马,齐王的总是比田忌的要好一点。于是每次和齐王赛马,田忌总会输600银币。
田忌很沮丧,直到他遇到了著名的军师――孙膑。田忌采用了孙膑的计策之后,三场比赛下来,轻松而优雅地赢了齐王200银币。这实在是个很简单的计 策。由于齐王总是先出最好的马,再出次好的,所以田忌用常规马对齐王的超级马,用自己的超级马对齐王的上级马,用自己的上级马对齐王的常规马,以两胜一负 的战绩赢得200银币。实在很简单。
如果不止三匹马怎么办?这个问题很显然可以转化成一个二分图最佳匹配的问题。把田忌的马放左边,把齐王的马放右边。田忌的马A和齐王的B之间,如果 田忌的马胜,则连一条权为200的边;如果平局,则连一条权为0的边;如果输,则连一条权为-200的边……如果你不会求最佳匹配,用最小费用最大流也可 以啊。 然而,赛马问题是一种特殊的二分图最佳匹配的问题,上面的算法过于先进了,简直是杀鸡用牛刀。现在,就请你设计一个简单的算法解决这个问题。
输入输出格式
输入格式:
第一行一个整数n,表示他们各有几匹马(两人拥有的马的数目相同)。第二行n个整数,每个整数都代
表田忌的某匹马的速度值(0 <= 速度值<=
100)。第三行n个整数,描述齐王的马的速度值。两马相遇,根据速度值的大小就可以知道哪匹马会胜出。如果速度值相同,则和局,谁也不拿钱。
【数据规模】
对于20%的数据,1<=N<=65;
对于40%的数据,1<=N<=250;
对于100%的数据,1<=N<=2000。
输出格式:
仅一行,一个整数,表示田忌最大能得到多少银币。
输入输出样例
3
92 83 71
95 87 74
200 这是一道让人吐血的好题。。 先来想想贪心策略(这里一定要理清思路,慢慢来,别急):
如果总是用最弱的马 去打对面最强的马,可能不是最优,因为这里有平局的情况存在,选择平局可能比赢给最强的马更合算
(譬如:田忌 2 3 10 齐威王:2 8 9)
因此,我们要这样去分析:
先看最弱的马之间的实力,如果我方最弱的马比对方最弱的马强,就直接怼掉。这个比较显然,既然我方最弱的马更强,那么我方其它马一定可以怼掉对方最弱的马,但杀鸡焉用牛刀?
如果我方的马比对方的马弱或者相等:
有一种策略是用最弱的马去怼最强的马,让“炮灰”的作用发挥到极值,
另一种策略是先看最强的马之间的关系。 我们来分别讨论这两种策略,并证明两种策略都是正确的:
1、用最弱的马去怼最强的马,这样输了一盘,但这一盘是早晚要输的。如果最弱的马等于对方最弱的马,那么怼掉对方最强马,一定有其它马可以赢回来;如果最弱的马小于对方最弱的马,那么必然小于对方所有马,这是必然的。因此应让它去怼掉对方最强的,让我放最强的能够成功得分道路进一步开阔。
2、先看最强的马之间的关系。如果我方最强马比对方更强,就怼掉,否则就应该让最弱的马去怼对方最强的马。因为我方最强的马虽然打不过敌方最强马,但说不定可以打过第二强、第三强……但是最弱的马却一定赢不了所有的马。
两条结合着来,差不多了就。。。
但是还有一种特殊情况:最弱的马平局,最强的马平局,且最弱的马等于最强的马
这时所有对决均为平局,直接输出答案即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) > (b) ? (b) : (a))
#define lowbit(a) ((a) & (-(a))) int read()
{
int x = 0;char ch = getchar();char c = ch;
while(ch > '9' || ch < '0')c = ch, ch = getchar();
while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
if(c == '-')return -x;
return x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 2000 + 10; int n,tian[MAXN],qi[MAXN];
int ans; inline void init()
{
n = read();
for(int i = 1;i <= n;i ++)
{
tian[i] = read();
}
std::sort(tian + 1, tian + 1 + n);
for(int j = 1;j <= n;j ++)
{
qi[j] = read();
}
std::sort(qi + 1, qi + 1 + n);
}
inline void put()
{
printf("%d", ans * 200);
}
inline void tan()
{
int head1 = 1,tail1 = n,head2 = 1,tail2 = n;
while(head1 <= tail1)
{
if(tian[head1] > qi[head2]) head1 ++,head2 ++,ans ++;
else if(tian[head1] < qi[head2]) head1 ++,tail2 --,ans --;
else//平局
{
if(tian[tail1] > qi[tail2])tail1 --, tail2 --, ans ++;
else if(tian[head1] < qi[tail2])head1 ++, tail2 --, ans--;//注意!!
else break;
}
}
} int main()
{
init();
tan();
put();
return 0;
}