首页 > 代码库 > [codevs2181]田忌赛马

[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;
}

 

[codevs2181]田忌赛马