[codevs2181]田忌赛马
[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; }