POJ 2287 Tian Ji -- The Horse Racing(贪心 记忆化搜索)
POJ 2287 Tian Ji -- The Horse Racing
题意
田忌赛马的故事,相信大家都知道,不多赘述。田忌和国王各有 n 匹马,每匹马都有一个能力值,两匹马赛跑的话,能力值高者胜。田忌每胜一局,就能获得200元奖赏,请问田忌最多能得到多少奖赏。
思路
贪心可以想到,如果当前一定会输,田忌就派最小的马;如果能赢,派最大的去赢;如果打平,就搜索一下,取派最小和派最大中的更优解。
这个状态我们可以用\(f[i][j]\)表示,表示的是田忌手上的马还剩下第 i 匹到第 j 匹,闭区间。根据上面的贪心策略做转移即可。
这题有贪心的双指针做法,但是我放在这里是希望大家能用记忆化搜索来写这道题,这是帮助理解区间DP的一道很好的例题。而且这种区间两头取的模型,你们以后也会常常见到,一般这个模型的题目,写记忆化搜索会比递推更好写,更容易处理边界条件。
实现
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1005;
int n;
int a[N], b[N]; //a是田忌 b是国王
int f[N][N]; //F(i,j,k) 在第i轮比赛的时候 田忌剩下的马是[j, k]
bool cmp(int a, int b) {return a > b;}
int dfs(int l, int r, int cur) //第几轮
{
if(cur == n + 1) return 0;
if(f[l][r] != -1) return f[l][r];
if(a[l] > b[cur])
return f[l][r] = dfs(l + 1, r, cur + 1) + 1;
else if(a[l] < b[cur])
return f[l][r] = dfs(l, r - 1, cur + 1) - 1;
else
return f[l][r] = max(dfs(l + 1, r, cur + 1), dfs(l, r - 1, cur + 1) - 1);
}
int main()
{
while(scanf("%d", &n))
{
if(!n) break;
memset(f, -1, sizeof f);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++)
scanf("%d", &b[i]);
sort(a + 1, a + n + 1, cmp);
sort(b + 1, b + n + 1, cmp);
printf("%d\n", 200 * dfs(1, n, 1));
}
}