首页 > 其他分享 >洛谷题单指南-动态规划2-P1004 [NOIP2000 提高组] 方格取数

洛谷题单指南-动态规划2-P1004 [NOIP2000 提高组] 方格取数

时间:2024-04-29 12:22:58浏览次数:31  
标签:NOIP2000 dp1 int 洛谷题 P1004 路径 起点 && dp

原题链接:https://www.luogu.com.cn/problem/P1004

题意解读:从起点走到终点,走两次,计算最大路径和,第一次走过的点数值变为0。

解题思路:

直观上思考,

可以先从起点走到终点,计算最大路径和,并记录走过的所有点,然后把所有点的数值置为0,

再从起点走到终点,计算最大路径和,

把两次的最大路径和加起来即可,

而从起点到终点的最大路径和类似于数字三角形问题

设dp[i][j]表示从起点走到(i,j)的最大路径和,有dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + a[i][j]

下面实现代码:

80分代码:

#include <bits/stdc++.h>
using namespace std;

struct point
{
    int x, y;
};

const int N = 15;
int a[N][N];
int dp1[N][N], dp2[N][N];
point from[N][N]; //记录每个点从哪个点走过来
int n;

int main()
{
    cin >> n;
    int x, y, z;
    while(cin >> x >> y >> z)
    {
        if(x == 0 && y == 0 && z == 0) break;
        a[x][y] = z;
    }

    //走第一遍
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(dp1[i-1][j] >= dp1[i][j-1]) from[i][j] = {i - 1, j};
            else from[i][j] = {i, j - 1};
            dp1[i][j] = max(dp1[i-1][j], dp1[i][j-1]) + a[i][j];
        }
    }
    //将起点到终点路径中的点数字清0
    int ti = n, tj = n;
    a[1][1] = 0;
    while(ti != 0 || tj != 0)
    {
        a[ti][tj] = 0;
        point p = from[ti][tj];
        ti = p.x, tj = p.y;
    }
    //走第二遍
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            dp2[i][j] = max(dp2[i-1][j], dp2[i][j-1]) + a[i][j];
        }
    }
    cout << dp1[n][n] + dp2[n][n];
    return 0;
}

为什么只能得部分分?

原因在于分开两次计算,每次计算路径最大值都是局部最优,且第一次计算最大值之后会对第二次计算最大值造成影响,不符合DP的特性。

那么,如何保证两次路径总和最大?可以从起点同时分两路走到终点,保证中间的每一步路径之和都是最大的,这样到终点的路径之和也是最大的!

设dp[i][j][k][l]表示从起点同步走到(i,j)(k,l)时,两条路径之和的最大值

那么,考虑最后一步,可能有四种组合:

1、从(i-1, j)走到(i, j),从(k-1, l)走到(k, l),状态转移表示为dp[i][j][k][l] = dp[i-1][j][k-1][l] + a[i][j] + a[k][l]

2、从(i, j-1)走到(i, j),从(k-1, l)走到(k, l),状态转移表示为dp[i][j][k][l] = dp[i][j-1][k-1][l]  + a[i][j] + a[k][l]

3、从(i-1, j)走到(i, j),从(k, l-1)走到(k, l),状态转移表示为dp[i][j][k][l] = dp[i-1][j][k][l-1]  + a[i][j] + a[k][l]

4、从(i, j-1)走到(i, j),从(k, l-1)走到(k, l),状态转移表示为dp[i][j][k][l] = dp[i][j-1][k][l-1]  + a[i][j] + a[k][l]

注意:由于第一次走过的点第二次变为0,所以在这里同步走时可以认为如果(i,j)(k,l)重合,即i == k && j == l,则权值只加一次

所以if(i == k && j == l) dp[i][j][k][l] -= a[i][j]

对四种情况取max即可。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 15;
int a[N][N];
int dp[N][N][N][N]; //dp[i][j][k][l]表示从起点同步走到(i,j)(k,l)时,两条路径之和的最大值
int n;

int main()
{
    cin >> n;
    int x, y, z;
    while(cin >> x >> y >> z)
    {
        if(x == 0 && y == 0 && z == 0) break;
        a[x][y] = z;
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            for(int k = 1; k <= n; k++)
            {
                for(int l = 1; l <= n; l++)
                {
                    dp[i][j][k][l] = max(max(dp[i-1][j][k-1][l], dp[i][j-1][k-1][l]), max(dp[i-1][j][k][l-1], dp[i][j-1][k][l-1])) + a[i][j] + a[k][l];
                    if(i == k && j == l) dp[i][j][k][l] -= a[i][j]; //由于第一次走过的点第二次变为0,所以在这里同步走时可以认为如果(i,j)(k,l)重合,即i == k && j == l,则权值只加一次
                }
            }
        }
    }
    cout << dp[n][n][n][n];
    
    return 0;
}

 

标签:NOIP2000,dp1,int,洛谷题,P1004,路径,起点,&&,dp
From: https://www.cnblogs.com/jcwy/p/18164024

相关文章

  • 洛谷题单指南-动态规划2-P2679 [NOIP2015 提高组] 子串
    原题链接:https://www.luogu.com.cn/problem/P2679题意解读:在a中按顺序挑选k个子串,使得这些子串连在一起正好和b相等,求方案数。解题思路:这样的题目,无外乎两个思路:DFS暴搜(得部分分)、动态规划动态规划不好想,还是先暴搜吧!1、DFS暴搜搜索的思路就是:从a起始位置开始,一直找到跟b前......
  • 洛谷题单指南-动态规划2-P1439 【模板】最长公共子序列
    原题链接:https://www.luogu.com.cn/problem/P1439题意解读:求最长公共子序列的长度。解题思路:1、O(n^2)的方法:动态规划设两个排列为a,b设dp[i][j]表示a[1~i]与b[1~j]的最长公共子序列长度根据公共子序列结尾是否包含a[i]、b[j]是否相等分情况讨论:如果a[i]==b[j]  则结尾......
  • 洛谷题解-官方题单-递归与递推
    P1255数楼梯原题链接题目描述楼梯有N阶,上楼可以一步上一阶,也可以一步上二阶。编一个程序,计算共有多少种不同的走法。对于60%的数据,N≤50;对于100%的数据,1≤N≤5000。思路:每次有2种方法上楼梯,要么上一阶,要么上二阶。第一种:得50分的做法是可以用递归来解:点击查看代码......
  • 洛谷题单指南-动态规划2-P2758 编辑距离
    原题链接:https://www.luogu.com.cn/problem/P2758题意解读:对a字符串最少操作几次可以变成b字符串,看似无从下手,可以从内部递推关系着手。解题思路:设dp[i][j]表示将a字符串1~i变成b字符串1~j的最少操作次数,字符串下标从1开始。如何思考递推?可以从最后一步为切入点!最后一步对a[i]......
  • 洛谷题单指南-动态规划2-P1874 快速求和
    原题链接:https://www.luogu.com.cn/problem/P1874题意解读:一个数字字符串s,分解成几个整数,和为n,计算最少加号个数,也就是计算最少分解的整数个数-1。解题思路:此题虽然分类在动态规划,但数据量不大,DFS更加直观和易于理解,所以采用DFS暴搜+剪枝来解决。搜索思路是对数字字符串依次枚......
  • 洛谷题单指南-动态规划2-P4933 大师
    原题链接:https://www.luogu.com.cn/problem/P4933题意解读:求有多少个子序列可以组成等差序列解题思路:1、暴力DFS如果实在想不出动规的方法,对于n<=20的数据,可以DFS枚举所有子序列的子集,再判断是否是等差数列。30分代码:#include<bits/stdc++.h>usingnamespacestd;const......
  • 洛谷题单指南-动态规划2-P1725 琪露诺
    原题链接:https://www.luogu.com.cn/problem/P1725题意解读:走过一系列格子之后,冰冻指数之和最大,相当于计算最大子序列的和。解题思路:设a[0~n]保存所有冰冻指数设dp[i]表示以第i号格子为终点所能获得的最大冰冻指数设j表示i的前一个格子,也就是从j可以移动到i已知i,则j的范围也......
  • 洛谷题单指南-动态规划2-P1020 [NOIP1999 提高组] 导弹拦截
    原题链接:https://www.luogu.com.cn/problem/P1020题意解读:拦截系统发射导弹的高度依次不增,计算能拦截的最大导弹数以及需要几套拦截系统。解题思路:问题1:最多能拦截多少导弹?由于发射导弹高度不增,所以求一个最长不增子序列即可得到最大拦截数。方法一、O(n^2)做法:动态规划。采......
  • 洛谷题单指南-动态规划1-P1064 [NOIP2006 提高组] 金明的预算方案
    原题链接:https://www.luogu.com.cn/problem/P1064题意解读:用固定钱数购买最大价值的物品。解题思路:背包问题,背包问题里的体积相当于物品价格,价值相当于价格*重要度物品分为主件、附件,主件最多有0/1/2个附件,要选附件必须选相应主件,因此在递推计算dp[j]总价格j能购买的最大价......
  • 洛谷题单指南-动态规划1-P3842 [TJOI2007] 线段
    原题链接:https://www.luogu.com.cn/problem/P3842题意解读:计算1-n的最短路,且每行要覆盖线段。解题思路:既然要每行覆盖线段,那往下一行走时,必然是从线段的端点往下,有可能是从左端点往下,也有可能是从右端点往下。当已知第i行,从1走到第i行的左端点且要覆盖第i行线段的路程可以计算......