zoukankan      html  css  js  c++  java
  • [dp] Jzoj P5770 可爱精灵宝贝

    Description

    Branimirko是一个对可爱精灵宝贝十分痴迷的玩家。最近,他闲得没事组织了一场捉精灵的游戏。游戏在一条街道上举行,街道上一侧有一排房子,从左到右房子标号由1到n。
    刚开始玩家在k号房子前。有m个精灵,第i只精灵在第A[i]栋房子前,分值是B[i],以及它在T[i]秒内(含)存在,之后消失。Branimirko可以选择移动至相邻的房子,耗时1秒。抓住精灵不需要时间,精灵被抓住后消失。时间从第1秒开始。Branimirko能最多获得多少分值和。
     
     

    Input

    输入的第1行为三个正整数n,k,m。
    接下来m行描述精灵的信息,分别为A[i],B[i],T[i]。
     

    Output

    输出Branimirko能最多获得多少分值和。
     
     

    Sample Input

    10 5 4
    1 30 4
    3 5 7
    7 10 12
    9 100 23
     

    Sample Output

    115
     
     

    Data Constraint

    20%的数据:m≤10
    40%的数据:m≤20
    k≤n≤1000,m≤100,A[i] ≤N,B[i] ≤100,T[i] ≤2000,所有数为正整数。
     
     

    Hint

    很遗憾,它恰好不能抓住在一号房子前的精灵。
    如果T[1]改成5,答案就是145

    90%题解

    • 其实就是一个水法,只考虑一个折回的话
    • 直接枚举到左端点折回或到右端点折回
    • 暴力判断

    100%题解

    • 对于数据,是不只有一个折回的,因为会存在一种这样的情况:
    • 向左走到某个点后,向右边恰好有一个点的时间可行,然后到了这个点后,左边又有一个点恰好时间可行,这样就不止一个折回了
    • 考虑一下dp
    • 设f[t][l][r][0/1]表示 当前时间为t 走过的区间为[l,r] 0表示在l 1表示在r 的最大分数
    • 那么对于[l,r]中间的点可以不用管,这时可以肯定的
    • 考虑如何转移,如果当前在l,可以考虑走到l-1或者到r再走到r+1
    • 如果在r,可以考虑走到r+1或者走到l再走到l-1
    • 最后的ans就是在dp转移过程中求max

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 using namespace std;
     7 struct edge{int a,b,t;}e[1010];
     8 int f[2005][103][103][2],n,m,k,ans,mx,w;
     9 bool cmp(edge x,edge y){ return x.a<y.a; }
    10 int dis(int x,int y) { return abs(e[x].a-e[y].a); }
    11 int main()
    12 {
    13     //freopen("go.in","r",stdin);
    14     //freopen("go.out","w",stdout);
    15     scanf("%d%d%d",&n,&k,&m);
    16     for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].t),mx=max(mx,e[i].t);
    17     m++,e[m]=edge{k,0,mx};
    18     sort(e+1,e+m+1,cmp);
    19     memset(f,-63,sizeof(f));
    20     for (int i=1;i<=m;i++)
    21         if (e[i].a==k&&e[i].b==0) 
    22             w=i;
    23     f[0][w][w][0]=f[0][w][w][1]=0;
    24     for (int i=w-1;i>=1;i--)
    25     {
    26         int tim=e[w].a-e[i].a;
    27         f[tim][i][w][0]=f[dis(w,i+1)][i+1][w][0]+((tim<e[i].t)?e[i].b:0);
    28         ans=max(ans,f[tim][i][w][0]);
    29     }
    30     for (int i=w+1;i<=m;i++)
    31     {
    32         int tim=e[i].a-e[w].a;
    33         f[tim][w][i][1]=f[dis(i-1,w)][w][i-1][1]+((tim<e[i].t)?e[i].b:0);
    34         ans=max(ans,f[tim][w][i][1]);
    35     }
    36     for (int i=1;i<=mx;i++)
    37         for (int l=1;l<=w-1;l++)
    38             for (int r=w+1;r<=m;r++)
    39             {
    40                 f[i][l][r][0]=max(f[max(i-dis(l,l+1),0)][l+1][r][0],f[max(i-dis(l,r),0)][l+1][r][1])+((i<e[l].t)?e[l].b:0);
    41                 f[i][l][r][1]=max(f[max(i-dis(r-1,r),0)][l][r-1][1],f[max(i-dis(l,r),0)][l][r-1][0])+((i<e[r].t)?e[r].b:0);
    42                 ans=max(ans,max(f[i][l][r][0],f[i][l][r][1]));
    43             }
    44     printf("%d",ans);
    45     return 0;
    46 }
  • 相关阅读:
    Qt状态机实例
    <STL> accumulate 与 自定义数据类型
    <STL> 容器混合使用
    散列表(C版)
    Canonical 要将 Qt 应用带入 Ubuntu
    <STL> set随笔
    C++ 文件流
    视频播放的基本原理
    <STL> pair随笔
    c++ 内存存储 解决char*p, char p[]的问题
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9433530.html
Copyright © 2011-2022 走看看