题意:两个人各有n匹马,给出每匹马的速度,n场比赛中,问第一个人最多能赢多少场.\(n<=2000\)
分析:其实就是跟田忌赛马的贪心策略差不多:如果我速度最大的马能赢对面速度最大的马,肯定用.如果我速度最小的马能赢对面速度最小的马,也肯定用.否则就用我速度最小的马去消耗掉对面速度最大的马.
根据这个贪心策略我们有两种实现方式,一是直接按照贪心策略来模拟.
把两方的马都从小到大排序,然后模拟n场比赛的情况即可.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=2005;
int a[N],b[N];
int main(){
int n=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=n;++i)b[i]=read();
sort(a+1,a+n+1);sort(b+1,b+n+1);
int i1=1,i2=1,j1=n,j2=n,ans=0;
for(int i=1;i<=n;++i){
if(a[j1]>b[j2])++ans,--j1,--j2;//最大的能赢
else if(a[j1]<b[j2])--ans,++i1,--j2;//最大的不能赢,就拿最小的去消耗
else if(a[i1]>b[i2])++ans,++i1,++i2;//最小的能赢,这一句放这里或者放下面都可以
else{
//最大的打成平局的话,还是拿最小的去消耗,但是可能到了最后,我最小的与对面最大的也打成了平局
if(a[i1]<b[j2])--ans;//这里一定要有这个判断
++i1;--j2;
}
}
printf("%d\n",ans*200);
return 0;
}
另一种方法是转换成DP来实现.设\(g[i][j]\)表示我的第i匹马与对方第j匹马比赛是否能赢(赢为1,平局为0,输为-1),\(f[i][j]\)表示前i场比赛中,我出了j(第1到j)匹好马,i-j(第i-j到n)匹劣马的最大收益.
\(f[i][j]=max(f[i-1][j]+g[n-(i-j)+1][i],f[i-1][j-1]+g[j][i])\)
为了方便,我们规定对面的出马顺序是从强到弱.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=2005;
int a[N],b[N],f[N][N],g[N][N];
int main(){
int n=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=n;++i)b[i]=read();
sort(a+1,a+n+1);reverse(a+1,a+n+1);
sort(b+1,b+n+1);reverse(b+1,b+n+1);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
if(a[i]>b[j])g[i][j]=1;
if(a[i]==b[j])g[i][j]=0;
if(a[i]<b[j])g[i][j]=-1;
f[i][j]=-1e9;
}
for(int i=1;i<=n;++i){
f[i][0]=f[i-1][0]+g[n-i+1][i];
f[i][i]=f[i-1][i-1]+g[i][i];
for(int j=1;j<i;++j){
f[i][j]=max(f[i-1][j]+g[n-(i-j)+1][i],f[i-1][j-1]+g[j][i]);
}
}
int ans=0;
for(int i=0;i<=n;++i)ans=max(ans,f[n][i]);
printf("%d\n",ans*200);
return 0;
}