NOIP 2000 提高组 洛谷1004题(方格取数)解题思路与C++代码解析

贾蔷
• 阅读 52

一、题目描述 简要描述题目:例如,在一个n×n的方格图中,每个格子包含一个正整数。需要选择两条从左上角到右下角的路径,路径可重复经过格子,但两条路径除起点和终点外不能相交。求两条路径数字和的最大值。

二、解题思路与算法分析

  1. 问题分析 1.问题核心是求解两条不交叉路径的最优组合,属于路径规划与组合优化问题。 2.直接暴力枚举路径组合的时间复杂度极高(O(2^n×n)),需采用动态规划降低复杂度。 3.关键点:如何定义状态以表示两条路径的当前位置,并确保状态转移时不交叉。
  2. 动态规划设计

(1)状态定义使用四维数组f[k][i][j]表示: k:两条路径共同走过的步数(即第k步); i:第一条路径当前所在的行坐标; j:第二条路径当前所在的列坐标。状态值f[k][i][j]为两条路径分别走到(i,j)和某个位置时的最大数字和。

(2)边界条件 初始状态:f[0][1][1] = g[1][1](两条路径均从起点(1,1)出发,数字和为起点格子值)。 其他状态初始化为负无穷(-0x3f),避免非法状态影响结果。

(3)状态转移方程分情况讨论: 当i == j时,两条路径在同一位置(重复点),只能同时向下或向右移动: (注:g[i][k+2-i]表示当前重复点的数字,因为两条路径同时移动一步。) 当i!= j时,两条路径独立移动,可分别向下或向右: (注:g[i][k+2-i]和g[j][k+2-j]分别表示两条路径当前位置的数字。) (4)最终答案:f[2*n-2][n][n](两条路径均到达右下角时的最大和)。

  1. 优化技巧 空间优化:由于状态转移仅依赖前一步的四个状态,可使用滚动数组进一步降低空间复杂度,但用户代码已通过三维数组实现(f[k][i][j]),有效避免了高维数组的存储问题。 边界处理:通过min(n, k+1)限制循环范围,避免无效计算。

三、完整代码

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 15; 
int g[N][N], f[N*2][N][N]; 

int main() {
    int n, x, y, v;
    cin >> n; 

    while((cin >> x >> y >> v) && (x || y || v)) {
        g[x][y] = v; 
    }

    memset(f, -0x3f, sizeof f);
    f[0][1][1] = g[1][1];

    for(int k = 1; k <= 2*n-2; ++k) { 
        for(int i = 1; i <= min(n, k+1); ++i) { 
            for(int j = 1; j <= min(n, k+1); ++j) { 
                int &val = f[k][i][j]; 
                val = max({
                    f[k-1][i][j],       
                    f[k-1][i-1][j],     
                    f[k-1][i][j-1],     
                    f[k-1][i-1][j-1]   
                });
                if(i == j) val += g[i][k+2-i]; 
                else val += g[i][k+2-i] + g[j][k+2-j]; 
            }
        }
    }
    cout << f[2*n-2][n][n] << endl; 
    return 0;
}

原文:NOIP 2000 提高组 洛谷1004题(方格取数)解题思路与C++代码解析

点赞
收藏
评论区
推荐文章
Kubrnete Kubrnete
4年前
基于活动选择问题的贪心算法
目录问题描述:(问题描述%3A)输入格式(输入格式)输出格式(输出格式)算法描述(算法描述与分析)算法分析(算法分析)算法图示(图解)问题描述:Coda从0时刻开始观看直播,到t时刻结束。一共有n场直播可被选择,已知所有直播场次的起止时间和主播名称,其中第i场直播从ai时刻开始,
cpp加油站 cpp加油站
4年前
题解5道c++面试题第一期(含解题思路、答案解析和实现代码)
本篇文章送上5道c/c面试题目,并附上答案、解题思路以及扩展知识。1.求下面函数的返回值cinclude<stdio.hintfunc(intx)intiCnt0;while(x)iCnt;xx&(x1);returniCnt;intmain()printf("cnt%d\n",func(9999
DaLongggggg DaLongggggg
4年前
python刷题-特殊回文数
问题描述  123321是一个非常特殊的数,它从左边读和从右边读是一样的。  输入一个正整数n,编程求所有这样的五位和六位十进制数,满足各位数字之和等于n。输入格式  输入一行,包含一个正整数n。输出格式  按从小到大的顺序输出满足条件的整数,每个整数占一行。样例输入52样例输出899998989989998899数据规模和约定 
Patrick Patrick
4年前
【分治法】解决中位数问题、格雷码问题以及分治法直接折半存在的问题讨论————武汉理工大学算法分析实验1
AlgorithmExperiment算法分析课实验分治法的核心思想是将问题分为若干子问题去,使规模一步步缩小,最终分到一步就能得出结果。要注意每个子问题需要性质相同而且相互不重复。采用分治法完成如下任务:i.中位数问题问题描述设X0:n1和Y0:n–1为两个数组,每个数组中含有n个已排好序的数。找出X和Y
Stella981 Stella981
3年前
LeetCode 5561. 获取生成数组中的最大值
文章目录1\.题目2\.解题1\.题目给你一个整数n。按下述规则生成一个长度为n1的数组nums:nums00nums11当2<2i<n时,nums2inumsi
Stella981 Stella981
3年前
LeetCode 92. 反转链表 II(Reverse Linked List II)
题目描述反转从位置_m_到_n_的链表。请使用一趟扫描完成反转。说明:1≤ _m_ ≤ _n_ ≤链表长度。示例:输入:12345NULL,m2,n4输出:14325NULL解题思路本题类似于反转链表
Stella981 Stella981
3年前
Codeforces997C Sky Full of Stars 【FMT】【组合数】
题目大意:一个$n\n$的格子,每个格子由你填色,有三种允许填色的方法,问有一行或者一列相同的方案数。题目分析:标题的FMT是我吓人用的。一行或一列的问题不好解决,转成它的反面,没有一行和一列相同的方案数。从一个方向入手,比如列,把一列看成一个整体。把颜色看成二进制数,$001$,$010$,$100$。那么一列构成了一个长度为$3
可莉 可莉
3年前
16. 数值的整数次方(剑指 Offer 题解Java版)
文章目录16\.数值的整数次方题目链接题目描述解题思路实现代码16\.数值的整数次方题目链接NowCoder题目描述        给定一个double类型的浮点数
Wesley13 Wesley13
3年前
67,盛最多水的容器
给定 _n_ 个非负整数 _a_1,_a_2,...,_a_n,每个数代表坐标中的一个点 (_i_, _ai_)。在坐标内画 _n_ 条垂直线,垂直线 _i_ 的两个端点分别为 (_i_, _ai_)和(_i_,0)。找出其中的两条线,使得它们与 _x_ 轴共同构成的容器可以容纳最多的水。说明:你不能倾斜容器,且 _n_ 的值至少为2。!
贾蔷 贾蔷
6天前
力扣1137题 解题思路和步骤 C++代码实现,力扣一共多少题
一、题目分析力扣1137题要求我们找到第N个泰波那契数。泰波那契数的定义是:T00,T11,T21,且在n0的条件下Tn3TnTn1Tn2。,当n4时,T4T3T2T14。这道题主要考查我们对递归或动态规划的理解和运用。在思考解题方法时,我们