洛谷 P1650 田忌赛马(dp)

传送门


解题思路

本题从暴力dfs入手,推出dp转移方程。
先进行排序,速度越大编号越大。
假设齐王从最大开始的出马,dfs(now,l,r)表示齐王出到编号为now的马,田忌还剩下l-r之间的马(因为田忌一定是要么出最大的马,要么出最小的马)。
分类讨论,当田忌最大的马大于齐王,则一定拿下这场比赛;
当田忌最大的小于齐王,则一定演下这场比赛;
当两者最大的马相等,则两种都有可能,答案取max。
这样原始代码就出来了:

int dfs(int now,int l,int r){
	if(now==0) return 0;
	if(a[r]>b[now]) return 200+dfs(now-1,l,r-1);
	if(a[r]<b[now]) return dfs(now-1,l+1,r)-200;
	return max(dfs(now-1,l,r-1),dfs(now-1,l+1,r)-200);
}

再加个记忆化或者将其变成for循环,就变成了dp。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=2005;
int n,a[maxn],b[maxn],dp[maxn][maxn];
template<class T>inline void read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
int main(){
	ios::sync_with_stdio(false);
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;i++) read(b[i]);
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	for(int now=1;now<=n;now++){
		for(int l=1;l<=n;l++){
			int r=now+l-1;
			if(a[r]>b[now]) dp[now][l]=200+dp[now-1][l];
			else if(a[r]<b[now]) dp[now][l]=dp[now-1][l+1]-200;
			else dp[now][l]=max(dp[now-1][l],dp[now-1][l+1]-200);	
		}
	}
	cout<<dp[n][1];
    return 0;
}
posted @ 2021-09-26 16:31  尹昱钦  阅读(142)  评论(0编辑  收藏  举报