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

     

  • 相关阅读:
    hdu 2647 Reward
    hdu 2094 产生冠军
    hdu 3342 Legal or Not
    hdu 1285 确定比赛名次
    hdu 3006 The Number of set
    hdu 1429 胜利大逃亡(续)
    UVA 146 ID Codes
    UVA 131 The Psychic Poker Player
    洛谷 P2491消防 解题报告
    洛谷 P2587 [ZJOI2008]泡泡堂 解题报告
  • 原文地址:https://www.cnblogs.com/Aloyd/p/9338340.html
Copyright © 2011-2022 走看看