zoukankan      html  css  js  c++  java
  • 【洛谷P6855】走方格

    题目

    题目链接:https://www.luogu.com.cn/problem/P6855
    \(n\times m\) 的方格矩阵,小 A 从 \((1,1)\) 出发到 \((n,m)\) ,只能向下或向右走,获得的分数为他经过方格的权值之和。

    已知每个方格 $(i,j) $的权值 \(a_{i,j}\),你可以将其中任意一个方格上的权值变为 \(0\),求变化后小 A 最多能获得分数的最小值

    思路

    首先我们发现,改动为 \(0\) 的格子一定在最长路径上,否则改了这个格子最长路径长度没变,显然不是最优解。

    因为从点 \((1,1)\)\((n,m)\) 且只可以往下或往右的任意一条路径长度都为 \(n+m-1\),所以答案只可能是修改这 \(n+m-1\) 个点中的一个。

    我们先求出 \(f[i][j]\) 表示点 \((1,1)\)\((i,j)\) 的最长路径长度,\(g[i][j]\) 表示点 \((n,m)\)\(i,j\) 的最长路径长度,然后枚举最长路径上的每一个点 \((x,y)\),需要求出将这个点权值设为 \(0\) 之后从 \((1,1)\)\((n,m)\) 的最长路径。

    经过点 \((x,y)\) 的最长路径长度为 \(f[x][y]+g[x][y]-2\times a[x][y]\),对于不经过点 \((x,y)\) 的点,我们枚举这条路径从第 \(x\) 行走向第 \(x+1\) 行是在哪一列,设为 \(k\),那么设 \(h[k]\) 表示这条路径从第 \(x\) 行到第 \(x+1\) 行走的是第 \(k\) 列,且不经过 \((x,y)\) 的最长路径。

    那么有

    \[h[k]=\left\{\begin{matrix}-\infty\ (k=y)\\ \max(h[k-1],f[x-1][k])+a[x][k]\ (k\neq y)\end{matrix}\right. \]

    此时从第 \(k\) 列下去的路径长度最大值就是 \(h[k]+g[x+1][k]\)

    所以将 \((x,y)\) 赋值为 \(0\),路径长度最大值就是

    \[\max(h[k]+g[x+1][k],f[x][y]+g[x][y]-2\times a[x][y]) \]

    在所有答案中取 \(\min\) 即可。

    由于我们只尝试将 \(n+m-1\) 个点赋值为 \(0\),每个点计算复杂度是 \(O(n)\),总时间复杂度 \(O(n^2)\)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=2010;
    const ll Inf=1000000000000000000LL;
    int n,m;
    ll ans,f[N][N],g[N][N],h[N],a[N][N];
    
    int main()
    {
    	memset(f,0xcf,sizeof(f));
    	memset(g,0xcf,sizeof(g));
    	scanf("%d%d",&n,&m);
    	ans=Inf; f[0][1]=f[1][0]=g[n+1][m]=g[n][m+1]=0;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    		{
    			scanf("%lld",&a[i][j]);
    			f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];
    		}
    	for (int i=n;i>=1;i--)
    		for (int j=m;j>=1;j--)
    			g[i][j]=max(g[i+1][j],g[i][j+1])+a[i][j];
    	for (int x=n,y=m;x!=1 || y!=1;)
    	{
    		ll maxn=0;
    		h[0]=-Inf;
    		for (int i=1;i<=m;i++)
    		{
    			if (i==y) h[i]=-Inf;
    			else
    			{
    				h[i]=max(h[i-1],f[x-1][i])+a[x][i];
    				maxn=max(maxn,h[i]+g[x+1][i]);
    			}
    		}
    		maxn=max(maxn,f[x][y]+g[x][y]-a[x][y]*2LL);
    		ans=min(ans,maxn);
    		
    		if (x==1) y--;
    		else if (y==1) x--;
    		else if (f[x-1][y]>f[x][y-1]) x--;
    		else y--;
    	}
    	printf("%lld",min(ans,f[n][m]-a[1][1]));
    	return 0;
    }
    
  • 相关阅读:
    每日思考(2020/08/19)
    每日思考(2020/08/18)
    每日思考(2020/08/17)
    每日思考(2020/08/16)
    每日思考(2020/08/14)
    每日思考(2020/08/13)
    每日思考(2020/08/12)
    每日思考(2020/08/11)
    每日思考(2020/08/10)
    Hibernate入门第一讲——Hibernate框架的快速入门
  • 原文地址:https://www.cnblogs.com/stoorz/p/13768676.html
Copyright © 2011-2022 走看看