zoukankan      html  css  js  c++  java
  • P3335[ZJOI2013]蚂蚁寻路【dp】

    正题

    题目链接:https://www.luogu.com.cn/problem/P3335


    题目大意

    给出\(n\times m\)的网格,每个格子有权值。一个回路在格子的边上,要求有\(2\times k\)次左转,其他都是右转,且最后\(2\)次一定得是右转。

    求包含的格子权值和最大。

    \(1\leq n,m\leq 100,0\leq k\leq 10\)


    解题思路

    看起来很像插头\(dp\)对吧,但是因为最后两下得是右转所以不是插头\(dp\)

    画一下不难发现包围出来的图形的底部一定是平的,然后上面是一个凹凸的形状。且会有\(k+1\)个凸,\(k\)个凹。也就是将固定的底部划分成\(2\times k+1\)个凹凸相间的矩形。

    先枚举一个底部,然后考虑\(dp\)。设\(f_{j,p,h}\)表示现在到第\(j\)列,第\(p\)个正方形,高度为\(h\)时的最大权值。

    转移的时候根据\(p\)的奇偶性决定是在上还是在下,当然也可以直接延长这个矩形。

    做个前缀和优化就是\(O(n^2mk)\)的了


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=110;
    int n,m,k,a[N][N],s[N][N],f[N][30][N],g[N][30][N][2],ans;
    int main()
    {
    	scanf("%d%d%d",&n,&m,&k);k=k*2+1; 
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			scanf("%d",&a[i][j]);
    			s[i][j]=s[i-1][j]+a[i][j];
    		}
    	for(int p=1;p<=k;p++)
    		for(int h=1;h<=n;h++)
    			f[0][p][h]=g[0][p][h][0]=g[0][p][h][1]=-1e9;
    	ans=-1e9; 
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			for(int p=1;p<=k;p++){
    				for(int h=1;h<=i;h++)
    					f[j][p][h]=max(f[j-1][p][h],g[j-1][p-1][h][p&1])+s[i][j]-s[i-h][j];
    				g[j][p][1][1]=g[j][p][i][0]=-1e9;
    				for(int h=i-1;h>=1;h--)
    					g[j][p][h][0]=max(g[j][p][h+1][0],f[j][p][h+1]);
    				for(int h=2;h<=i;h++)
    					g[j][p][h][1]=max(g[j][p][h-1][1],f[j][p][h-1]);
    			}
    			for(int h=1;h<=i;h++)
    				ans=max(ans,f[j][k][h]);
    		}
    	printf("%d\n",ans); 
    	return 0;
    }
    
  • 相关阅读:
    Elasticsearch 缓存总结
    ElasticSearch-集群
    HTTP协议详解
    HTTPS总结
    ElasticSearch--Document
    正排索引和倒排索引
    线上OOM排查步骤总结
    线程池-四种拒绝策略总结
    netty篇-练手
    netty篇-UDP广播
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14604724.html
Copyright © 2011-2022 走看看