1. 程式人生 > 實用技巧 >PepperLa's Boast(單調佇列優化二維dp)

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\n",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\n", dp[n][m]);
65     }
66     return 0;
67 }