花园游戏 【动态规划】

(原题)题目链接:看樱花  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

 

原文地址:https://www.cnblogs.com/Aloyd/p/9338340.html