zoukankan      html  css  js  c++  java
  • 花园游戏 【动态规划】

    (原题)题目链接:看樱花  https://vijos.org/p/1627

    描述

      “妹妹背着洋娃娃,走到花园看樱花” – 我整个人都Hello kitty了。

    好了,闲话就说到这里,已知:这是一个1×N的花园(虽然比较奇怪),被分成了N个格子,每个格子里有一种神奇的樱花(我也不知道为什么神奇,反正洋娃娃看着高兴),看到第i个格子上的花洋娃娃会得到不同的满足度Ci(每个花的满足度只被计算一次)。现在妹妹会背着洋娃娃从任意格子走进花园,当然从第i个格子进去会消耗Di个单位的满足度,然后游历花园,在一个格子向右走需要耗费R个单位的满足度,向左走需要耗费L个单位的满足度,最后从第i个格子出花园又要耗费Fi个单位的满足度。

    接下来,我们需要设计一套游历方案,使得最终获得的总满足度最高(太低的话洋娃娃会……)

    格式

    输入格式

      第一行依次给出三个正整数N,L,R。

      第二行有N个整数,第i个数为Di。

      第三行有N个整数,第i个数为Fi。

      第四行有N个整数,第i个数为Ci。

    输出格式

      仅需要输出一行包括一个整数,表示最大获得的满足度为多少。

    样例1

    样例输入1

    5 1 1
    1 1 1 1 1
    1 1 1 1 1
    1 1 3 1 1

    样例输出1

    1

    限制

      各个测试点1s

    提示

      对于30%数据,N<=10。

      对于60%数据,N<=100。

      对于100%数据,N<=1000。

    来源

      Mrain 原创
      NOIP 2009·Dream Team 模拟赛 第一期 第三题

    分析:

      本来我是用的贪心的,但很无奈,错误的贪心;

      错误的贪心:

        直接向左刷一遍单向最优解Dp[i],再从左往右不计满足度去寻找最优解

        初始化Dp[i]

        同理向右刷一遍单向最优解Dp[i],再从右往左不计满足度去寻找最优解

        输出两个最优解的较大值

        错误就在于忽略了往返后能继续增长的满足度(即走回来继续走的所新得到的满足度都被我吃了)

      改进所得的动态规划:

        既然我错在往返后能继续增长的满足度,那我直接枚举往返后的两个端点就好了呀

        打个栗子:

          我们计算 i -> j 的最优情况 (i > j 即 i 在 j 右边)

             也就是计算 i -> j 的路上的满足度(和损耗) 以及 i 向右再回来能得到的最大值(也就是我之前贪心的东西)

          见下面部分代码     

     1 /*
     2     Right[j] :走到 j 的左面再回来所能增加的满足度(为零代表不走)
     3     Left[i]   :同理
     4     Pre       :用前缀和的方式记录 1 -> i 或者 1 -> j 的满足度
     5 */
     6 
     7 int ans=-1e9;
     8 for(int i=1;i<=N;i++)
     9 for(int j=i;j<=N;j++){       // 从 i 进去 从 j 出来
    10     int t=Right[j]+Left[i]+Pre[j]-Pre[i-1]-R*(j-i)-D[i]-F[j];
    11     ans=max(t,ans);
    12 }
    Code

        

        i 在 j 的左边的情况同理哦

    Code

     1 #include<queue>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 int N;
     8 int L,R;
     9 int D[1005];
    10 int F[1005];
    11 int C[1005];
    12 void Init(){
    13     scanf("%d%d%d",&N,&L,&R);
    14     for(int i=1;i<=N;i++)
    15      scanf("%d",&D[i]);
    16     for(int i=1;i<=N;i++)
    17      scanf("%d",&F[i]);
    18     for(int i=1;i<=N;i++)
    19      scanf("%d",&C[i]);
    20     return ;
    21 }
    22 int Pre[1005];
    23 int Left[1005];
    24 int Right[1005];
    25 
    26 void Solve(){
    27     Right[N]=0,Left[1]=0;
    28     for(int i=2;i<=N;i++)
    29      Left[i]=max(Left[i-1]-L-R+C[i-1],Left[i]);
    30     for(int i=N-1;i>0;i--)
    31      Right[i]=max(Right[i],Right[i+1]-L-R+C[i+1]);
    32 
    33     Pre[1]=C[1];Pre[0]=0;
    34     for(int i=2;i<=N;i++)
    35      Pre[i]=Pre[i-1]+C[i];
    36     int ans=-1e9;
    37     for(int i=1;i<=N;i++)
    38     for(int j=i;j<=N;j++){
    39         int t=Right[j]+Left[i]+Pre[j]-Pre[i-1]-R*(j-i)-D[i]-F[j];
    40         ans=max(t,ans);
    41     }
    42     for(int i=1;i<=N;i++)
    43     for(int j=1;j<=i;j++){
    44         int t=Left[j]+Right[i]+Pre[i]-Pre[j-1]-L*(i-j)-D[i]-F[j];
    45         ans=max(t,ans);
    46     }
    47     printf("%d
    ",ans);
    48     return ;
    49 }
    50 int main(){
    51     Init();
    52     Solve();
    53     return 0;
    54 }
    AC code

     

  • 相关阅读:
    mysql 查询优化 ~ select count 知多少
    mongodb 案例 ~ 经典故障案例
    printk 驱动调试
    21天学通C++学习笔记(七):函数
    OPC UA
    MQTT
    分库分表
    水平、垂直权限问题(横向越权与纵向越权)
    数据库中的行转列和列转行
    面试知识点
  • 原文地址:https://www.cnblogs.com/Aloyd/p/9338340.html
Copyright © 2011-2022 走看看