HDU 1052(贪心 田忌赛马)

6 篇文章 0 订阅

题目链接:hdu 1052

题目大意

田忌和齐王赛马,各自有n匹马,每匹马有一个能力值,能力值大的获胜,赢一局得200分输一局-200分平局得0分.问田忌最多得到多少分?

分析

根据题意很容易想到二分图匹配,将每一组田忌比齐王大的连上一条边,这样通过二分图匹配可以求得田忌最多胜多少局。但仔细想了之后发现平局的情况会比较难以处理。

这是一道贪心题,只是需要花些功夫来证明贪心策略的正确性,一开始的策略想复杂了(田忌的每匹马去赢它刚好能够赢的齐王的马,出一看没什么问题,具体做的时候会发现细节还是很难处理)

看了网上很多博客发现基本都没去证明其中一个策略的正确性(贪心题你不证明清楚这不是耍流氓吗),后来培训的时候还一知半解地还给大一把这道题地证明讲了,问听懂没有,回答听懂了(我也是醉了,我自己都没懂我是怎么把他们讲懂的?)后来仔细想了很久总算搞懂了。

现在来详细分析一下这道题的解题思路:

这里用T来表示田忌的马,Q来表示齐王的马
先分类
T<Q: 说明 TQ ,无论这样都是输,要输的最有价值,用 TQ
T>Q: 齐王最小的马无论和田忌哪匹马比都是输,田忌肯定是选择用他最小的马去比。
T=Q 这个时候情况就要复杂一点了,再分为三种情况:
a :T>Q TQ 最有价值
b :T<QQQ
c :T=Q这是这道题的关键了,先说结论:这个时候也是用田忌最小的马去和齐王最大的马比最划算。别的博客里都是一笔带过,难道这是显而易见的吗?

现在我们要证明在 T=QT=Q 的情况下 (TQ)(TQ)
我们先画出分别做出这两个选择后的局面:

假设第一种局面得到的结果是 ans1 第二种是 ans2 ,我们要证明的是 ans1ans2+1 (因为我们到达局面一是输了一局,而到局面二是平的)
这里写图片描述
此时,最终 T 只有两种情况,要么和 Q 去平要么输给齐王的匹马:
这里写图片描述
1.如果 T 是和 Q 平,我们可以通过在局面二引入 T ,让 T 去赢 Q ,然后删掉 T 此时的局面就是局面一, ans1=ans2+1
2.如果 T 是输给齐王的某匹马,我们可以通过在局面二引入 T ,让 T 去赢这匹马,然后删掉 T 此时的局面就是局面一, ans1>ans2+1 (因为撤销了一场输掉的比赛,增加了一场赢的比赛)
这里写图片描述
这样我们就证明了 ans1ans2+1
所以我觉得这个证明过程不是显而易见的啊!!!

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
using namespace std;
int n;
int ans;
int T[1005];
int K[1005];
int main()
{
    while(scanf("%d",&n)!=EOF && n)
    {
          for(int i=1;i<=n;i++)scanf("%d",&T[i]);
          for(int i=1;i<=n;i++)scanf("%d",&K[i]);
          sort(T+1,T+n+1);
          sort(K+1,K+n+1);
          int win=0,lose=0;
          int t_low=1,t_fast=n;
          int k_low=1,k_fast=n;
          while(t_low <= t_fast )
          {
                if(T[t_low] < K[k_low])
                {
                      lose++;
                      t_low++;
                      k_fast--;
                }
                else if(T[t_low] > K[k_low])
                {
                      win++;
                      t_low++;
                      k_low++;
                }
                else
                {
                      if(T[t_fast] > K[k_fast])
                      {
                            t_fast--;
                            k_fast--;
                            win++;
                      }
                      else
                      {
                            if(T[t_low]<K[k_fast])lose++;
                            t_low++;
                            k_fast--;
                      }
                }
          }
          printf("%d\n",200*(win-lose));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值