HDU 4374 One hundred layer(DP+单调队列优化)
比赛的时侯非常暴力来了个N*M*T的算法,状态方程虽然好想,不会优化。。认真学习一下单调队列优化,看了很多博客+题解,其实原理也不难理解。
这个题状态转移,从左边来的 dp[i][j] = dp[i-1][k] + dis(k,j) 先预处理出一个sum数组存每一行前i个元素的和,dp[i][j] = dp[i-1][k] + sum[i][j]-sum[i][k-1];
这就可以用单调队列了,在队列首部存放dp[i-1][k]-sum[i][k-1]最大值的下标。明白了原理后,看了一份题解,想了好一会为什么队头总是最大的,问了下学长,这个队列的关键是队头,小的元素可以直接覆盖进入队列,而不是插入进入队列,所以不可能存在队列中元素比队头大的。看了好久,最近学习效率好低啊。。。
代码参考题解。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 int p[110][10001],dp[111][10001]; 5 int sum[110][10001],que[10001]; 6 int max(int a,int b) 7 { 8 return a > b ? a:b; 9 } 10 int main() 11 { 12 int i,j,n,m,x,t,ans,str,end; 13 while(scanf("%d%d%d%d",&n,&m,&x,&t)!=EOF) 14 { 15 memset(dp,128,sizeof(dp)); 16 for(i = 1; i <= n; i ++) 17 { 18 for(j = 1; j <= m; j ++) 19 { 20 scanf("%d",&p[i][j]); 21 sum[i][j] = sum[i][j-1] + p[i][j]; 22 } 23 } 24 for(i = x; i >= x - t && i >= 1; i --) 25 dp[1][i] = sum[1][x] - sum[1][i-1]; 26 for(i = x + 1; i <= x + t && i <= m; i ++) 27 dp[1][i] = sum[1][i] - sum[1][x-1]; 28 for(i = 2;i <= n;i ++) 29 { 30 str = end = 0; 31 for(j = 1;j <= m;j ++) 32 { 33 //覆盖进入队列 34 while(str < end&&dp[i-1][j]-sum[i][j-1]>dp[i-1][que[end-1]]-sum[i][que[end-1]-1]) 35 end --; 36 que[end++] = j; 37 dp[i][j] = dp[i-1][que[str]]+sum[i][j]-sum[i][que[str]-1]; 38 if(j - que[str] >= t)//维护队列在t范围内 39 str ++; 40 } 41 str = end = 0; 42 for(j = m;j >= 1;j --) 43 { 44 while(str < end&&dp[i-1][j]+sum[i][j]>dp[i-1][que[end-1]]+sum[i][que[end-1]]) 45 end -- ; 46 que[end++] = j; 47 dp[i][j] = max(dp[i][j],dp[i-1][que[str]]+sum[i][que[str]]-sum[i][j-1]); 48 if(que[str] - j >= t) 49 str++; 50 } 51 } 52 ans = dp[n][1]; 53 for(i = 2;i <= m;i ++) 54 { 55 ans = max(ans,dp[n][i]); 56 } 57 printf("%d\n",ans); 58 } 59 return 0; 60 }