• [TJOI 2013]拯救小矮人


    Description

    一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯。即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口。对于每一个小矮人,我们知道他从脚到肩膀的高度Ai,并且他的胳膊长度为Bi。陷阱深度为H。如果我 们利用矮人1,矮人2,矮人3,。。。矮人k搭一个梯子,满足A1+A2+A3+....+Ak+Bk>=H,那么矮人k就可以离开陷阱逃跑了,一 旦一个矮人逃跑了,他就不能再搭人梯了。
    我们希望尽可能多的小矮人逃跑, 问最多可以使多少个小矮人逃跑。

    Input

    第一行一个整数N, 表示矮人的个数,接下来N行每一行两个整数Ai和Bi,最后一行是H。(Ai,Bi,H<=10^5)

    Output

    一个整数表示对多可以逃跑多少小矮人

    Sample Input1

    2
    20 10
    5 5
    30

    Sample Output1

    2

    Sample Input2

    2
    20 10
    5 5
    35

    Sample Output2

    1

    HINT

    数据范围
    30%的数据 N<=200
    100%的数据 N<=2000

    题解

    这道题话说网上很多题解都是错的耶...

    基本上都是用“身高+臂长”作为逃生能力来进行解释...

    但是如果按照普遍的题解,我们无法解释在$DP$的过程中“第$i$个人不选的情况”...

    打个比方,我举出一组反例:

    3

    5 1

    1 6

    4 4

    12

    按普遍的题解来说我们按所谓的“逃生能力”排序,为$5+1$,$1+6$,$4+4$。

    那么我们按“逃生顺序”来,我们一个都不能逃出(第一个人就是$1+5+1+4<12$)。然而若我们让最后一个人先走($5+1+4+4>12$)显然能逃出。

    显然这个顺序并不是所谓的“逃生顺序”,那要怎么做?

    首先我们还是是要按照身高+臂长来排序,但是为什么呢?

    大概证明如下:

    考虑对于最上面的两个人,下面的人梯高度一定

    如果无论怎样都出不去,那相对顺序肯定是无所谓的

    如果怎么都能出去,那相对顺序肯定也是无所谓的

    关键就是剩下的情况,两个人都有机会逃出去,但是排的先后顺序会影响逃跑结果

    这种情况下就只能让身高+臂长比较小的人较先离开,按照刚才的说法,因为他的逃生能力比较弱

    但是对吗?

    随之而来的又有一个问题,只贪心到底行不行,而刚刚举出的反例显然说明了这个问题

    这怎么办呢?

    这时我们就发现“这种情况下就只能让身高+臂长比较小的人较先离开,因为他的逃生能力比较弱”这句话是错的

    但是它为我们提供了一个思路,那就是最终的最优逃出方案一定可以是一个按照“身高+臂长”递增的序列

    这个怎么证呢?就是当我们发生上述冲突时,我们肯定是选择让高个的留下并且永远留下,矮个那个先走,这样就满足了性质

    然后就可以$DP$了!

    所以!!我们排序+$DP$的原因不是XX放在XX前面一定更优,而是最终的逃跑序列一定是一个“身高+臂长”递增的序列,为了方便$DP$,所以我们才要排序!!!!

    (部分题解源commonc的博客

     1 //It is made by Awson on 2017.9.27
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime> 
     6 #include <queue>
     7 #include <stack>
     8 #include <string>
     9 #include <cstdio>
    10 #include <vector>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define Min(a, b) ((a) < (b) ? (a) : (b))
    16 #define Max(a, b) ((a) > (b) ? (a) : (b))
    17 #define LL long long
    18 using namespace std;
    19 const int N = 2000;
    20 void read(int &x) {
    21     char ch; bool flag = 0;
    22     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    23     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    24     x *= 1-2*flag;
    25 }
    26 
    27 struct tt {
    28     int a, b;
    29     bool operator < (const tt &q) const{
    30         return a+b < q.a+q.b;    
    31     }
    32 }a[N+5];
    33 int n, h;
    34 int f[N+5];
    35 
    36 void work() {
    37     read(n);
    38     for (int i = 1; i <= n; i++)
    39         read(a[i].a), read(a[i].b);
    40     sort(a+1, a+n+1);
    41     read(h);
    42     memset(f, -1, sizeof(f));
    43     int ans = 0;
    44     f[0] = 0;
    45     for (int i = 1; i <= n; i++) f[0] += a[i].a;
    46     for (int i = 1; i <= n; i++) {
    47         for (int j = ans; j >= 0; j--) {
    48             if (f[j]+a[i].b >= h)
    49                 f[j+1] = Max(f[j+1], f[j]-a[i].a);
    50             if (f[ans+1] >= 0) ans++;
    51         }
    52     }
    53     printf("%d
    ", ans);
    54 }
    55 int main() {
    56     work();
    57     return 0;
    58 }
  • 相关阅读:
    docker容器升级脚本
    Haproxy状态监控配置教程
    负载均衡之Haproxy配置详解(及httpd配置)
    升级代码脚本
    升级数据库脚本(加入事务)
    监控端口,新疆模拟用户登录脚本
    mongodb3.2系统性学习——3、update()操作
    Java Socket编程
    php错误级别设置
    php 用于绘图使用的颜色数组
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7604324.html
Copyright © 2020-2023  润新知