[codevs2181]田忌赛马
试题描述
中国古代的历史故事“田忌赛马”是为大家所熟知的。话说齐王和田忌又要赛马了,他们各派出N匹马,每场比赛,输的一方将要给赢的一方200两黄金,如果是平局的话,双方都不必拿出钱。现在每匹马的速度值是固定而且已知的,而齐王出马也不管田忌的出马顺序。请问田忌该如何安排自己的马去对抗齐王的马,才能赢取最多的钱?
输入
第一行为一个正整数n ,表示双方马的数量。
第二行有N个整数表示田忌的马的速度。
第三行的N个整数为齐王的马的速度
输出
仅有一行,为田忌赛马可能赢得的最多的钱,结果有可能为负。
输入示例
3 92 83 71 95 87 74
输出示例
200
数据规模及约定
n <= 1000
题解
很好的一道题,结合了贪心和 dp 的思想。
不难想到对两个序列排序,那么我们就可以从左往右依次考虑田忌的马了,对于田忌一匹马,它可以:
1.) 赢掉齐王速率尽量小的一匹马(或平局)
2.) 输给齐王速率尽量大的一匹马
于是我们就可以设计 f(i, j) 表示对战了 i 匹马,其中用掉了齐王的前 j 匹和后 i-j 匹,转移并不难。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 2010
#define oo 2147483647
int n, f[maxn][maxn], A[maxn], B[maxn];
int calc(int a, int b) { return ((a >= b) - (a <= b)) * 200; }
int main() {
n = read();
for(int i = 1; i <= n; i++) A[i] = read();
for(int i = 1; i <= n; i++) B[i] = read();
sort(B + 1, B + n + 1);
sort(A + 1, A + n + 1);
for(int i = 1; i <= n; i++)
for(int j = 0; j <= i; j++)
f[i][j] = max(i - 1 >= j ? f[i-1][j] + calc(A[i], B[n-(i-j)+1]) : -oo, j ? f[i-1][j-1] + calc(A[i], B[j]) : -oo);
int ans = 0;
for(int i = 0; i <= n; i++) ans = max(ans, f[n][i]);
printf("%d\n", ans);
return 0;
}