PepperLa's Boast(单调队列优化二维dp)

PepperLa's Boast(单调队列优化二维dp)

 

题意:一个人在(1,1)点处,由于这个n*m的二维空间着火了,他要从(1,1)点逃到(n,m)点。给出 n*m 矩阵内每一个坐标的的值代表这里的空气,限制是空气小于等于零的地方不能呼吸。这个人的每一步只可以走到三个方向:(x+1,y+1)  or (x+1,y) or (x,y+1) ,每次可以走一步到有空气的地方进行换气(呼吸),也可以消耗 U 体积的空气走 K 步到有空气的地方进行换气呼吸。问当到达(n,m)点时,这个人的肺中最多存有多少空气

题解:

 做到这题的时候还没有掌握单调队列QAQ

所以WA:

  1 // 又是看了一晚上的dp不知道思路错在哪里
  2 // 其实是不可以这么一步一步贪心去取的最大值的
  3 // 因为我到当前点i,j才减上一个点要去掉的u
  4 // 有可能之前的大,但是他要减u,到这儿变小了
  5 // 而之前小的, 但是他中间不经过无空气地带, 到这儿不减u, 这样得到的答案反而比上面的值打
  6 // 所以, 很明显这要再来一重循环(跑每一个到当前点距离不超过点)去一个个试试了
  7 // 这复杂度应该是O(n*m*k),所以要优化了
  8 
  9 #include <iostream>
 10 #include <bits/stdc++.h>
 11 using namespace std;
 12 typedef long long ll;
 13 const int maxn = 1e3+10;
 14 
 15 ll ans;
 16 int n,m;
 17 ll k,u;
 18 ll dp[maxn][maxn];
 19 ll a[maxn][maxn];
 20 ll z[maxn][maxn];
 21 
 22 struct node{
 23     int id;
 24     int u,v;
 25 };
 26 
 27 bool cmp(node x, node y){
 28     if( x.u==y.u ) return x.v>y.v;
 29     return x.u>y.u;
 30 }
 31 
 32 int judge(int i,int j){
 33     node f[5];
 34     f[1].id=1; f[1].u=dp[i-1][j-1]; f[1].v=z[i-1][j-1];
 35     f[2].id=2; f[2].u=dp[i-1][j]; f[2].v=z[i-1][j];
 36     f[3].id=3; f[3].u=dp[i][j-1]; f[3].v=z[i][j-1];
 37     sort(f+1,f+1+3,cmp);
 38     return f[1].id;
 39 }
 40 
 41 int main()
 42 {
 43     while( ~scanf("%d%d%lld%lld",&n,&m,&k,&u)){
 44         memset(dp,-1,sizeof(dp));
 45         for(int i=1;i<=n;i++){
 46             for(int j=1;j<=m;j++){
 47                 scanf("%lld",&a[i][j]);
 48             }
 49         }
 50 
 51         dp[1][1] = a[1][1];
 52         if( a[1][1]>=u ) z[1][1] = k;
 53         else z[1][1] = 0;
 54 
 55         for(int i=1;i<=n;i++){
 56             for(int j=1;j<=m;j++){
 57                 if( i==1 && j==1 ) continue;
 58                 else if( i==1 ){
 59                     if( dp[i][j-1]<=0 ){
 60                         continue;
 61                     }
 62 
 63                     if( a[i][j]<=0 ){
 64                         z[i][j] = z[i][j-1]-1;
 65                         if( z[i][j]<=0 ){
 66                             dp[i][j] = -1;
 67                         }else{
 68                             dp[i][j] = dp[i][j-1];
 69                         }
 70                     }
 71                     else{
 72                         if( a[i][j-1]>0 ) dp[i][j] = dp[i][j-1]+a[i][j];
 73                         else dp[i][j] = dp[i][j-1]-u+a[i][j];
 74 
 75                         if( dp[i][j]>=u ) z[i][j] = k;
 76                         else z[i][j] = 0;
 77                     }
 78                 }
 79                 else if( j==1 ){
 80                     if( dp[i-1][j]<=0 ) continue;
 81 
 82                     if( a[i][j]<=0 ){
 83                         z[i][j] = z[i-1][j]-1;
 84                         if( z[i][j]<=0 ){
 85                             dp[i][j] = -1;
 86                         }else{
 87                             dp[i][j] = dp[i-1][j];
 88                         }
 89                     }
 90                     else{
 91                         if( a[i-1][j]>0 ) dp[i][j] = dp[i-1][j]+a[i][j];
 92                         else dp[i][j] = dp[i-1][j]-u+a[i][j];
 93                         if( dp[i][j]>=u ) z[i][j] = k;
 94                         else z[i][j] = 0;
 95                     }
 96                 }
 97                 else{
 98                     if( a[i][j]<=0 ){
 99                         int f = judge(i,j);
100                         if( f==1 ){
101                             if( dp[i-1][j-1]<=0 ) continue;
102 
103                             z[i][j] = z[i-1][j-1]-1;
104                             if( z[i][j]<=0 ){
105                                 dp[i][j] = -1;
106                             }
107                             else{
108                                 dp[i][j] = dp[i-1][j-1];
109                             }
110                         }
111                         else if( f==2 ){
112                             if( dp[i-1][j]<=0 ) continue;
113 
114                             z[i][j] = z[i-1][j]-1;
115                             if( z[i][j]<=0 ){
116                                 dp[i][j] = -1;
117                             }
118                             else{
119                                 dp[i][j] = dp[i-1][j];
120                             }
121                         }
122                         else if( f==3 ){
123                             if( dp[i][j-1]<=0 ) continue;
124 
125                             z[i][j] = z[i][j-1]-1;
126                             if( z[i][j]<=0 ){
127                                 dp[i][j] = -1;
128                             }
129                             else{
130                                 dp[i][j] = dp[i][j-1];
131                             }
132                         }
133                     }
134                     else{
135                         int f = judge(i,j);
136                         if( f==1 ){
137                             if( dp[i-1][j-1]<=0 ) continue;
138 
139 
140                             if( a[i-1][j-1]>0 ){
141                                 z[i][j] =  k;
142                                 dp[i][j] = dp[i-1][j-1]+a[i][j];
143                             }
144                             else{
145                                 dp[i][j] = dp[i-1][j-1]-u+a[i][j];
146                                 if( dp[i][j]>=u ) z[i][j] = k;
147                                 else z[i][j] = 0;
148                             }
149                         }
150                         else if( f==2 ){
151                             if( dp[i-1][j]<=0 ) continue;
152 
153                             if( a[i-1][j]>0 ){
154                                 z[i][j] =  k;
155                                 dp[i][j] = dp[i-1][j]+a[i][j];
156                             }
157                             else{
158                                 dp[i][j] = dp[i-1][j]-u+a[i][j];
159                                 if( dp[i][j]>=u ) z[i][j] = k;
160                                 else z[i][j] = 0;
161                             }
162                         }
163                         else if( f==3 ){
164                             if( dp[i][j-1]<=0 ) continue;
165 
166                             if( a[i][j-1]>0 ){
167                                 z[i][j] =  k;
168                                 dp[i][j] = dp[i][j-1]+a[i][j];
169                             }
170                             else{
171                                 dp[i][j] = dp[i][j-1]-u+a[i][j];
172                                 if( dp[i][j]>=u ) z[i][j] = k;
173                                 else z[i][j] = 0;
174                             }
175                         }
176                     }
177                 }
178             }
179         }
180         printf("%lld
",dp[n][m]);
181     }
182     return 0;
183 }
View Code

AC_Code:可以先看一看我的这篇博客-->here

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=1e3+10;
 5 const int inf = 0x3f3f3f3f;
 6 
 7 struct node{
 8     ll val;
 9     int idx;
10 };
11 int n,m,k,u;
12 int a[maxn][maxn];
13 ll dp[maxn][maxn];
14 deque<node>col_q[maxn], row_q;
15 
16 void _max(ll &x, ll y ){
17     if( x<y ) x=y;
18 }
19 //纵向每列建一个列单调队列,在每行从左到右转移时候再建一个行单调队列,入队的都是列单调队列的队首元素
20 //为什么呢?因为从左边或者从左上转移过来,都是用单调队列后从左边转移过来啊
21 
22 int main()
23 {
24     memset(dp,-1,sizeof(dp));
25     while( ~scanf("%d%d%d%d",&n,&m,&k,&u) ){
26         for(int i=1;i<=n;i++){
27             for(int j=1;j<=m;j++){
28                 scanf("%d",&a[i][j]);
29                 dp[i][j] = -1;
30             }
31         }
32         dp[1][1] = a[1][1];
33         for(int i=1;i<=m;i++) col_q[i].clear();
34         for(int i=1;i<=n;i++){
35             row_q.clear();
36             for(int j=1;j<=m;j++){
37                 while( col_q[j].size() && col_q[j].front().idx<i-k ) col_q[j].pop_front();//注意这里是<i-k, 不是<=i-k,举个栗子就知道了从1走5步不是到5是到6,那么从6退5补是到6-5=1处
38                 while( row_q.size() && row_q.front().idx<j-k ) row_q.pop_front();
39 
40                 if( a[i][j]>0 ){
41                     if( dp[i-1][j]!=-1 ) _max(dp[i][j], dp[i-1][j]+a[i][j]);
42                     if( dp[i][j-1]!=-1 ) _max(dp[i][j], dp[i][j-1]+a[i][j]);
43                     if( dp[i-1][j-1]!=-1 ) _max(dp[i][j], dp[i-1][j-1]+a[i][j]);
44 
45                     if( col_q[j].size() ){
46                         while( row_q.size() && row_q.back().val<=col_q[j].front().val ) row_q.pop_back();
47                         row_q.push_back(node{col_q[j].front().val, j});//暂时加入上方的push here
48                     }
49                     if( row_q.size() ) _max(dp[i][j], row_q.front().val+a[i][j]-u);
50                     if( col_q[j].size() ) row_q.pop_back();//然后删除, pop here
51                 }
52 
53                 if( dp[i][j]>=u ){
54                     while( col_q[j].size() && col_q[j].back().val<=dp[i][j]) col_q[j].pop_back();
55                     col_q[j].push_back(node{dp[i][j], i});
56                 }
57 
58                 if( col_q[j].size() ){
59                     while( row_q.size() && row_q.back().val<=col_q[j].front().val ) row_q.pop_back();
60                     row_q.push_back(node{col_q[j].front().val, j});
61                 }
62             }
63         }
64        printf("%lld
", dp[n][m]);
65     }
66     return 0;
67 }
原文地址:https://www.cnblogs.com/wsy107316/p/14146361.html