田忌赛马

洛咕

题意:两个人各有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
",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
",ans*200);
    return 0;
}
原文地址:https://www.cnblogs.com/PPXppx/p/11542369.html