tyvj1048 田忌赛马
描述
输入格式
第二行有N个整数表示田忌的马的速度。
第三行的N个整数为齐王的马的速度。
输出格式
测试样例1
输入
3
92 83 71
95 87 74
输出
200
这个问题很显然可以转化成一个二分图最佳匹配的问题。把田忌的马放左边,把齐王的马放右边。田忌的马A和齐王的B之间,如果田忌的马胜,则连一条权为200的边;如果平局,则连一条权为0的边;如果输,则连一条权为-200的边。
然而我们知道,二分图的最佳匹配算法的复杂度很高,无法满足N=2000的要求。
我们不妨用贪心思想来分析一下问题。因为田忌掌握有比赛的“主动权”,他总是根据齐王所出的马来分配自己的马,所以这里不妨认为齐王的出马顺序是按马的速度从高到低出的。由这样的假设,我们归纳出如下贪心策略:
1、如果田忌剩下的马中最强的马都赢不了齐王剩下的最强的马,那么应该用最差的一匹马去输给齐王最强的马。
2、如果田忌剩下的马中最强的马可以赢齐王剩下的最强的马,那就用这匹马去赢齐王剩下的最强的马。
3、如果田忌剩下的马中最强的马和齐王剩下的最强的马打平的话,可以选择打平或者用最差的马输掉比赛。
第一个贪心策略的证明:
此时田忌的所有马都赢不了齐王的马,所以无论用最慢马去输还是用最快的马去输都同样是输,而处于贪心的思想,我们应该保留相比之下更强的马,因此用最慢的马去输一定不会比用别的马去输来得劣,所以这是最优策略。
证毕。
第二个贪心策略的证明:
假设现在齐王剩下的最强的马是A,田忌剩下的最强的马是B,如果存在一种更优的比赛策略,让B的对手不是A,而使得田忌赢更多的钱的话,那么设此时A的对手是b,B的对手是a:
若b>A,则有B>a,b>A。这个结果和B>A,b>a是相同的。
若a<b≤A,则有B>a,b≤A。这个结果不如B>A,b>a来得优秀。
若b≤a≤A,则有B>a,b≤A。这个结果和B>A,b≤a是相同的。
由此可知,交换各自对手后,一定不会使得结果变劣,那么假设是不成立的。
证毕。
第三个贪心策略的证明:
因为田忌最快的马也只是和齐王的马打平,那么田忌只能选择平或输,选择平的话,当然只能用最快的马去平了;选择输的话当时是用最慢的马去输来得值得,这和第一个贪心策略的思路是一样的。
证毕。
我们发现,第三个贪心策略出现了一个分支:打平或输掉。如果穷举所有的情况,算法的复杂度将比求二分图最佳匹配还要高;如果一概而论的选择让最强的马去打平比赛或者是让最差的马去输掉比赛,则存在反例:
光是打平的话,如果齐王马的速度分别是1 2 3,田忌马的速度也是1 2 3,每次选择打平的话,田忌一分钱也得不到,而如果选择先用速度为1的马输给速度为3的马的话,可以赢得200两黄金。
光是输掉的话,如果齐王马的速度分别是1 3,田忌马的速度分别是2 3,田忌一胜一负,仍然一分钱也拿不到。而如果先用速度为3的马去打平的话,可以赢得200两黄金。
虽然因为第三个贪心出现了分支,我们不能直接的按照这种方法来设计出一个完全贪心的方法,但是通过上述的三种贪心策略,我们可以发现,如果齐王的马是按速度排序之后,从高到低被派出的话,田忌一定是将他马按速度排序之后,从两头取马去和齐王的马比赛。有了这个信息之后,动态规划的模型也就出来了!
设f[i,j]表示齐王按从强到弱的顺序出马和田忌进行了i场比赛之后,从“头”取了j匹较强的马,从“尾”取了i-j匹较弱的马,所能够得到的最大盈利。
状态转移方程如下:
f[i,j]=max{f[i-1,j]+g[n-(i-j)+1,i],f[i-1,j-1]+g[j,i]}
其中g[i,j]表示田忌的马和齐王的马分别按照由强到弱的顺序排序之后,田忌的第i匹马和齐王的第j匹马赛跑所能取得的盈利,胜为200,输为-200,平为0。
--------------分割线-----------------------------------------
俩数组 ,排序,l1=1; l2=1; r1=n; r2=n;
( 左向右 如果 a[l1]>b[l2] 则 l1:=l1+1; l2:=l2+1; ans:=ans+200;
右往左 如果 a[r1]>b[r2] 则 r1:=r1-1; r2:=r2-1; ans:=ans+200;
此时如果 a[l1]=b[r2] 则中间的数全相等,不用算了。。
如果 a[l1]<b[r2] 则 s:=s-200; l1:=l1+1; r2:=r2-1;)
继续() 的循环;
证明:
得到从左往右第一个 a[l1]<=b[l2] 和从右往左第一个 a[r1]<=b[r2] 时,
草稿纸上演算一下就知道。。此时不管b[l2]是否等于a[l1] b[r2]是否等于a[r1] 让a[l1]和b[r2] 比赛 总是最好情况之一;
-------------------------rzy------------
稍作简单分析
既可以知道如果自己最强的马打不过齐王的马就派出自己最弱的马
如果打的过的话就去把它灭了
这样一分析,就可以知道 只能从头尾取马
那就转换成了常见的dp的线性模型,类似于矩阵取数的题目了
方程就自然而然的出来了
f[i,j]=max{f[i-1,j]+g[n-(i-j)+1,i],f[i-1,j-1]+g[j,i]}
(小心j=0 和j=i 的情况。。我刚开始就这里挂掉了)
--------------------------------------------
贪心
1.当田忌最慢的马比齐王最慢的马快,赢一场先。因为始终要赢齐王最慢的马,不如用最没用的马来赢它。
2.当田忌最慢的马比齐王最慢的马慢,和齐王最快的马比,输一场。因为田忌最慢的马始终要输的,不如用它来消耗齐王最有用的马。
3.当田忌最慢的和齐王最慢的马慢相等时,分4和5讨论。
4.当田忌最快的马比齐王最快的马快时,赢一场先。因为最快的马的用途就是来赢别人快的马,别人慢的马什么马都能赢。
5.当田忌最快的马比齐王最快的马慢时,拿最慢的马和齐王最快的马比,输一场,因为反正要输一场,不如拿最没用的马输。
6.当田忌最快的马和齐王最快的马相等时,这就要展开讨论了,贪心方法是,拿最慢的马来和齐王最快的马比.
显然是正确的!!!
//--------------------
这里讨论另外一种方程形式:
先排序后肯定从两头取,这个问题上面大神都解释清了(我很弱小解释不能)……
既然从田忌马队两头取,那么可以用一个区间[l,r]表示田忌当前可选的马队,取l或者取r,这样剩下的区间就是[l+1,r]或者[l,r-1]
齐王的马可以利用田忌区间算出来,田忌区间长度是r-l+1,所以赛过n-(r-l+1)场,由此齐王当前的马就是n-(r-l+1)+1=n-r+l
这样方程就有了(递归运行记忆化,别的方法不会……不过应该循环也能写?):
pick(l,r)=max(pick(l+1,r)+g[l,n-r+l],pick(l,r-1)+g[r,n-r+l])
其实原理都差不多来着吧…………只是个人觉得这样好理解些…………
//copy //greedy
#include <cstdio>
#include <algorithm>
using namespace std;
const int M=;
int qt[][M];
int n;
int main()
{
scanf("%d",&n);
for (int i=;i>=;i--)
for (int j=;j<=n;j++)
scanf("%d ",&qt[i][j]);
int s=;
sort(qt[]+,qt[]+n+,[](int a,int b){ return a<b; });
sort(qt[]+,qt[]+n+,[](int a,int b){ return a<b; });
int i1=,i2=n,j1=,j2=n;
while (i1<=i2)
if (qt[][i1]<qt[][j1]) {i1++;j1++;s++;continue;} else
if (qt[][i1]>qt[][j1]) {s--;j1++;i2--;continue;} else
if (qt[][i1]==qt[][j1])
if (qt[][i2]<qt[][j2]) {i2--;j2--;s++;continue;} else {if (qt[][j1]<qt[][i2]) s--;j1++;i2--;continue;}
printf("%d",s*);
return ;
} //dp
#include <iostream>
#include <algorithm>
#include <cstring>
#define N 1005
using namespace std; int n, a[N], b[N];
int f[N][N];
/*
不妨设齐王的马是从快到慢出场的。
f[l][r]: 在田忌的可选区间为[l, r]的时候,能得到的最大奖金,此时已经赛过n - (r - l + 1)场,故此时出场的是齐王的第n - r + l匹马
f[l][r] = max (f[l + 1][r] + g (l, n - r + l), f[l][r - 1] + g (r, n - r + l))
田忌选最快的马 田忌选最慢的马
*/ inline int g (int x, int y)
{
if (a[x] < b[y])
return -;
if (a[x] > b[y])
return ;
return ;
} int work (int l, int r)
{
if (f[l][r] != -)
return f[l][r];
if (l == r)
return f[l][r] = g (l, n); f[l][r] = max (work (l + , r) + g (l, n - r + l), work (l, r - ) + g (r, n - r + l));
return f[l][r];
} bool cmp (int x, int y)
{ return x > y; } int main()
{
cin >> n;
for (int i = ; i <= n; i++)
cin >> a[i];
for (int i = ; i <= n; i++)
cin >> b[i]; sort (a + , a + n + , cmp);
sort (b + , b + n + , cmp);
memset (f, -, sizeof (f)); cout << work (, n) << endl;
return ;
}
tyvj1048 田忌赛马的更多相关文章
- [POJ2287][Tyvj1048]田忌赛马 (贪心+DP)
瞎扯 很经典的一道题 考前才打 我太菜了QAQ 就是先贪心排序了好 然后在DP 这样比直接DP更容易理解 (其实这题做法还有很多) 代码 #include<cstdio> #include ...
- nyoj 364 田忌赛马(贪心)
田忌赛马 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Here is a famous story in Chinese history. "That ...
- [codevs2181]田忌赛马
[codevs2181]田忌赛马 试题描述 中国古代的历史故事"田忌赛马"是为大家所熟知的.话说齐王和田忌又要赛马了,他们各派出N匹马,每场比赛,输的一方将要给赢的一方200两黄金 ...
- ACM 田忌赛马
田忌赛马 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Here is a famous story in Chinese history. "That ...
- TYVJ P1048 田忌赛马 Label:dp
描述 中国古代的历史故事“田忌赛马”是为大家所熟知的.话说齐王和田忌又要赛马了,他们各派出N匹马,每场比赛,输的一方将要给赢的一方200两黄金,如果是平局的话,双方都不必拿出钱.现在每匹马的速 ...
- HDUOJ-------1052Tian Ji -- The Horse Racing(田忌赛马)
Tian Ji -- The Horse Racing Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (J ...
- D - D 田忌赛马
D - D 田忌赛马 解题报告 hdu 1052 Tian Ji -- The Horse Racing 链接:http://acm.hust.edu.cn/vjudge/contest/v ...
- HDOJ-1052 田忌赛马(贪心)
田忌赛马 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述: Here is a famous story in Chinese history. "That was ...
- [洛谷P1650] 田忌赛马
贪心难题:总结贪心问题的一般思路 传送门:$>here<$ 题意 田忌和齐王各有n匹马,赛马时一一对应.赢+200,输-200,平+0. 问最多多少钱? 数据范围:$n \leq 2000 ...
随机推荐
- js数字格式化千分位格式
带小数点的 var a = 8462948.2453; console.log(a.toLocaleString()) //8,462,948.245 不带小数点的 num.toString().re ...
- C#里的指针
最近在复习C#基础这里,发现指针运算方式跟引用类型运算方式很相像. 指针里面存放的是表示内存地址的一段整数,所以任何整数类型指针之间都可以相互转换,因此带来了不安全性. ; long* b = &am ...
- HDU 1693 Eat the Trees(插头DP,入门题)
Problem Description Most of us know that in the game called DotA(Defense of the Ancient), Pudge is a ...
- 图书 Framework 设计指南: 可重用 .NET 库的约定、惯用法和模式 引出资料
文章:框架设计准则 --微软 地址:https://docs.microsoft.com/zh-cn/dotnet/standard/design-guidelines/index
- spring环境搭建(简单实例)
1使用Maven导入需要的依赖(在project标签下) <properties> <spring_version>3.2.2.RELEASE</spring_versi ...
- lintcode-49-字符大小写排序
49-字符大小写排序 给定一个只包含字母的字符串,按照先小写字母后大写字母的顺序进行排序. 注意事项 小写字母或者大写字母他们之间不一定要保持在原始字符串中的相对位置. 样例 给出"abAc ...
- WEBSTORM中html文件运行之后出现乱码的问题解决
出现如下问题: 解决方案: 1.点击"文件编码" 2.选择GBK 3.点击Reload. 4.此时,源代码中的中文字体会变成乱码,把这些乱码重新输入成原先的中文.然后运行html文 ...
- 使用emit发出信号
1. 信号声明 在发送信号的模块类头文件中声明信号函数 signals: void sendRate(QString rate); 2. 在发送模块的成员函数中发出信号 emit sendRate(u ...
- asp.net中的cookie
一.cookie导读,理解什么是cookie 1.什么是cookie:cookie是一种能够让网站服务器把少量数据(4kb左右)存储到客户端的硬盘或内存.并且读可以取出来的一种技术. 2.当你浏览某网 ...
- 使用XML传递数据
HTML <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF- ...