zoukankan      html  css  js  c++  java
  • UVALive 7146 (贪心+少许数据结构基础)2014acm/icpc区域赛上海站

    这是2014年上海区域赛的一道水题。请原谅我现在才发出来,因为我是在太懒了。当然,主要原因是我刚刚做出来。

    其实去年我就已经看到这道题了,因为我参加的就是那一场。但是当时我们爆零,伤心的我就再也没有看过那一场的题了。昨天我的队友的高中同学建议我们一起来打一打这场比赛吧,然后我才再次回顾这场比赛。结果一堆琐事,我一共也没有做多久的题,我的队友扎扎实实看了5个小时的题,把另一道水题给过了。全场我们也只过了那么一道题。学姐说,做重现赛和现场赛比较,需要去掉一题,那么我们又爆零了。

    题意:

    我方有n个人,敌方有m个人。每个人有攻击力a,防御力d。如果我方的人i攻击力比敌方的人j的防御力高,那么i可以杀死j,否则杀不死。当然,如果同时j的攻击力比i个防御力高,那么j同时会杀死i

    但是,每个人只能打一次,无论存活下来还是死去。

    求我方在杀死所有敌人的情况下,最多可以留下多少人?

    输入:

    首行一个整型t,表示共有t组数据。

    接下来,每组数据首行两个整型nm,分别表示我方人数和敌方人数。

    接下来n行,每行两个整型ad,表示我方某人的攻击力与防守力。

    接下来m行,每行两个整型ad,表示敌方某人的攻击力与防守力。

    输出:

    首先输出”Case #x: ”,x是数据组数。

    如果无法杀死敌方所有人,那么输出-1。否则输出我方幸存人数。

    题解:

    去年的时候这道题我是一点思路也没有,今年有了一点思路,然后顺利的tle了好几发。实际上我距离正确结果只差一步了,但是这一步就是咫尺天涯。

    1. 输入的时候我把敌人的攻击和防守反转一下输入,己方的正常输入。

    2. 我要把所有人都放在一起,按照攻击a从大到小排序。初始化ans = n;

    3. 所有人从大到小读取,直到读取到一个敌人为止。这样,我可以保证,我所有的读取到的我方的人都可以杀死当前的敌人,因为敌人的防守力参与了我方的攻击力的排序。

    4. 我要迅速的从我方已经读取的人中寻找一个既可以杀死敌人,又尽可能保存自己的人。即,将我方以读取的人按照防御从小到大排序,找到一个恰好可以防住当前敌人的人。然后将这个人从读取的己方人中删除。表示他杀掉了一个敌人,完成使命。当我方所有人都无法防住敌人的攻击,那就选一个防守最低的人来杀敌,同时也被杀,ans--; 继续读取数组。即,进行步骤3

    5. 当所有的敌人都被杀死时,输出结果。当遇到敌人但无人能杀掉他时,中断读取,输出-1

    写到这里可能有人会有疑问了——

    1. 为什么在寻找人时可以重新排序(将排好的序打乱)呢?

    因为我们只需要保证我们的人能够杀死敌人当前的人就行了。

    所以,我们先按照我方的攻击从大到小找人,敌人的防守从大到小找人。这样,我们已经找到的我方的人只要能够杀死当前的敌人,那么就肯定能杀死后面的敌人。那么我们找到的我方的人无论怎么打乱顺序都无所谓了,反正肯定都能杀死敌人。此时的攻击力的顺序已经没有意义了。

    1. 为什么从可以杀死敌人的我方人中选取刚好能够防住的,如果防不住则选取防最低的,而不直接选取防守最高的呢?

    因为,我们是按照我方攻击和敌方防守排的序,所以,无法保证后面防守低的敌人攻击也低。如果我们当前有两个人——

    攻击为10,防守为10

    攻击为10,防守为5

    先找到一个敌人——攻击为1,防守为6。那么如果用攻击为10,防守为10的我方士兵。那么如果下一个敌人是攻击为6,防守为1呢?如果用攻击为20,防守为5的,则我方会死一个人。而反过来就都能存活。

    如果敌人第一个攻击为11,防守为6,那么如果先用防守高的,则我方会死一个人   下一个敌人攻击为6,防守为6,我方又会死一个人。而反过来只会死一个人。

    在保证能够杀死敌人的情况下,优先使用防守低的人,保留防守高的人,能活则活,不能活的就给个死的最痛快的。

    然后我就如何将我方的人按照防守力进行第二次排序进行了“深入细致”的思考,结果得到的结论是——使用最快的排序!即k*log2(k)k表示当前满足条件的我方的人数。哦,我真是SB了!这样一来,我进行了m次排序,且排序长度最差情况是k == n一直到k == n-m+1。可以达到n*n*log2(n)。我不超时谁超时?

    后来看了题解,发现,可以用set来保存啊,这样就不需要每次都排一次序了,添加我方第k个人时时间复杂度是log2(k),很稳定,小于n*log2(n)

    我真是脑残了。明明都想到了可以如果把排序降到log2(n)的话一定能过,为什么就是想不到set每次操作是log2(n)呢?涨涨记性,嗯,一定要涨涨记性。

    当然,这道题因为会出现重复数据,那么需要用multiset,当然,使用方法大同小异。

    还有一点,学会了使用stlupper_bound()函数。返回值和参数都是一个当前容器的格式。

    ps. 当然代码和思路还有些区别,但区别不大。

    pss. 头一次写这么长的题解,赶上总结了……

    上代码——

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <algorithm>
     4 #include <set>
     5 using namespace std;
     6 
     7 const int N = 100010;
     8 
     9 struct Node
    10 {
    11     int a, d;
    12     int id;
    13 }s1[N], s2[N];
    14 
    15 int n, m, t;
    16 int ans;
    17 
    18 bool cmp(Node x, Node y)
    19 {
    20     return x.a > y.a;
    21 }
    22 
    23 void Init()
    24 {
    25     scanf("%d%d", &n, &m);
    26     for(int i = 0; i < n; i++)
    27     {
    28         scanf("%d%d", &s1[i].a, &s1[i].d);
    29         s1[i].id = 0;
    30     }
    31     for(int i = 0; i < m; i++)
    32     {
    33         scanf("%d%d", &s2[i].d, &s2[i].a);
    34         s2[i].id = 1;
    35     }
    36     sort(s1, s1+n, cmp);
    37     sort(s2, s2+m, cmp);
    38     ans = n;
    39 }
    40 
    41 void Work()
    42 {
    43     multiset <int> st;
    44     st.clear();
    45     for(int i = 0, j = 0; j < m; j++)
    46     {
    47         while(s2[j].a <= s1[i].a && i < n)
    48         {
    49             st.insert(s1[i].d);
    50             i++;
    51         }
    52         if(st.empty()) {ans = -1; return;}
    53         multiset<int>::iterator mid = st.upper_bound(s2[j].d);
    54         if(mid == st.end())
    55         {
    56             st.erase(st.begin());
    57             ans--;
    58         }
    59         else st.erase(mid);
    60     }
    61 }
    62 
    63 int main()
    64 {
    65     //freopen("test.in", "r", stdin);
    66     scanf("%d", &t);
    67     for(int tm = 1; tm <= t; tm++)
    68     {
    69         Init();
    70         Work();
    71         printf("Case #%d: %d
    ", tm, ans);
    72     }
    73 }
    View Code
  • 相关阅读:
    Linux用户行为日志审计
    日志分析-Web
    secedit.exe 本地审核
    StreamCQL
    一个关于缓存很好的文章~
    Java免费开源数据库、Java嵌入式数据库、Java内存数据库
    MySQL db优化
    威胁情报
    《javascript设计模式》读书笔记二(封装和隐藏信息)
    Mysql触发器
  • 原文地址:https://www.cnblogs.com/mypride/p/5024562.html
Copyright © 2011-2022 走看看