mirror of
https://gitcode.com/Zengtudor/alg2025.git
synced 2025-11-06 14:53:47 +00:00
refactor(P7074): 重构动态规划解法并优化路径计算逻辑
重构了P7074问题的解决方案,将原来的二维DP扩展为三维状态表示,以更精确地跟踪不同移动方向的最大路径和。新增了对特殊情况的处理(如单格、单列情况),并添加了详细注释说明算法逻辑。 同时清理了test.cpp文件中的冗余代码,仅保留main函数框架。
This commit is contained in:
parent
4e419a46c7
commit
9541f97f8b
94
src/10/31/P7074.cpp
Normal file
94
src/10/31/P7074.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// 使用 long long 防止整数溢出,因为路径和可能很大
|
||||||
|
using ll = long long;
|
||||||
|
|
||||||
|
// 定义一个非常小的数作为负无穷大,用于初始化dp数组
|
||||||
|
// 路径和可能为负,所以不能用0初始化
|
||||||
|
const ll INF = -1e18; // 1000*1000*10000 = 10^10,ll可以存下
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// 提高C++ IO效率
|
||||||
|
std::ios_base::sync_with_stdio(false);
|
||||||
|
std::cin.tie(NULL);
|
||||||
|
|
||||||
|
int n, m;
|
||||||
|
std::cin >> n >> m;
|
||||||
|
|
||||||
|
std::vector<std::vector<int>> a(n + 1, std::vector<int>(m + 1));
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
for (int j = 1; j <= m; ++j) {
|
||||||
|
std::cin >> a[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dp[i][j][k] 表示到达格子 (i, j) 的最大路径和
|
||||||
|
// k = 0: 最后一步是从左边 (i, j-1) 来的
|
||||||
|
// k = 1: 最后一步是从上面 (i-1, j) 来的 (向下移动)
|
||||||
|
// k = 2: 最后一步是从下面 (i+1, j) 来的 (向上移动)
|
||||||
|
std::vector<std::vector<std::vector<ll>>> dp(n + 2, std::vector<std::vector<ll>>(m + 2, std::vector<ll>(3, INF)));
|
||||||
|
|
||||||
|
// 起点 (1, 1) 初始化
|
||||||
|
// 到达 (1, 1) 本身,路径和就是 a[1][1]
|
||||||
|
// 逻辑上可以认为是从 (1, 0) 这个虚拟格子过来的
|
||||||
|
dp[1][1][0] = a[1][1];
|
||||||
|
|
||||||
|
// DP过程:逐列计算
|
||||||
|
for (int j = 1; j <= m; ++j) {
|
||||||
|
// Step 1: 从左边 (j-1) 列转移到当前 (j) 列
|
||||||
|
if (j > 1) {
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
// 从 (i, j-1) 点可以向右到达 (i, j)
|
||||||
|
// (i, j-1) 可能是从左/上/下三个方向到达的,取其中最大值
|
||||||
|
ll from_left = std::max({dp[i][j-1][0], dp[i][j-1][1], dp[i][j-1][2]});
|
||||||
|
// 如果前一格的所有状态都不可达,则当前状态也无法通过此路径到达
|
||||||
|
if (from_left != INF) {
|
||||||
|
dp[i][j][0] = from_left + a[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: 在当前列 j 内,进行向上/向下的更新
|
||||||
|
// 从上往下更新
|
||||||
|
for (int i = 2; i <= n; ++i) {
|
||||||
|
// 要到达 (i, j) 且最后一步是向下,必须从 (i-1, j) 过来
|
||||||
|
// 在 (i-1, j),不能是从 (i, j) 往下再往上,所以不考虑 dp[i-1][j][2]
|
||||||
|
ll from_up = std::max(dp[i-1][j][0], dp[i-1][j][1]);
|
||||||
|
if (from_up != INF) {
|
||||||
|
// 当前状态 dp[i][j][1] 可能已经被之前的计算更新过(或者没有)
|
||||||
|
// 需要和从 (i-1,j) 走过来的新路径和比较,取最大值
|
||||||
|
dp[i][j][1] = std::max(dp[i][j][1], from_up + a[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从下往上更新
|
||||||
|
for (int i = n - 1; i >= 1; --i) {
|
||||||
|
// 要到达 (i, j) 且最后一步是向上,必须从 (i+1, j) 过来
|
||||||
|
// 在 (i+1, j),不能是从 (i, j) 往上再往下,所以不考虑 dp[i+1][j][1]
|
||||||
|
ll from_down = std::max(dp[i+1][j][0], dp[i+1][j][2]);
|
||||||
|
if (from_down != INF) {
|
||||||
|
dp[i][j][2] = std::max(dp[i][j][2], from_down + a[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 终点是 (n, m)。到达该点的路径可能是从左边 (n, m-1) 或上面 (n-1, m) 来的。
|
||||||
|
// 所以取 dp[n][m][0] 和 dp[n][m][1] 的较大值。
|
||||||
|
// dp[n][m][2] 是从 (n+1, m) 来的,不合法,其值应为INF。
|
||||||
|
ll ans = std::max(dp[n][m][0], dp[n][m][1]);
|
||||||
|
|
||||||
|
// 对于只有一个格子的特殊情况(1x1)
|
||||||
|
if (n == 1 && m == 1) {
|
||||||
|
ans = a[1][1];
|
||||||
|
} else if (m == 1) { // 只有一列,只能往下走
|
||||||
|
// 只有一列时,没有从左边来的转移,dp[i][1][0]只在i=1时有值
|
||||||
|
// dp[i][1][1] 是从上往下累加的
|
||||||
|
ans = dp[n][1][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << ans << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -1,47 +0,0 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
const long long INF = -1e18;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
ios_base::sync_with_stdio(false);
|
|
||||||
cin.tie(NULL);
|
|
||||||
|
|
||||||
int n, m;
|
|
||||||
cin >> n >> m;
|
|
||||||
|
|
||||||
vector<vector<int>> a(n + 1, vector<int>(m + 1));
|
|
||||||
for (int i = 1; i <= n; ++i) {
|
|
||||||
for (int j = 1; j <= m; ++j) {
|
|
||||||
cin >> a[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<vector<long long>> dp(n + 2, vector<long long>(m + 2, INF));
|
|
||||||
|
|
||||||
dp[1][0] = 0;
|
|
||||||
|
|
||||||
for (int j = 1; j <= m; ++j) {
|
|
||||||
|
|
||||||
for (int i = 1; i <= n; ++i) {
|
|
||||||
dp[i][j] = dp[i][j - 1] + a[i][j];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 2; i <= n; ++i) {
|
|
||||||
dp[i][j] = max(dp[i][j], dp[i - 1][j] + a[i][j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = n - 1; i >= 1; --i) {
|
|
||||||
dp[i][j] = max(dp[i][j], dp[i + 1][j] + a[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << dp[n][m] << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
154
src/test.cpp
154
src/test.cpp
@ -1,155 +1,3 @@
|
|||||||
#include <bits/stdc++.h>
|
int main(){
|
||||||
#define int long long
|
|
||||||
using namespace std;
|
|
||||||
struct node
|
|
||||||
{
|
|
||||||
int date = 0;
|
|
||||||
int lan = 0;
|
|
||||||
int left = 0;
|
|
||||||
int right = 0;
|
|
||||||
int lanc = 0;
|
|
||||||
};
|
|
||||||
int n, q, m;
|
|
||||||
vector<int> a;
|
|
||||||
vector<node> tree;
|
|
||||||
void build(vector<node> &tree, vector<int> &a, int rt, int left, int right)
|
|
||||||
{
|
|
||||||
if(left == right)
|
|
||||||
{
|
|
||||||
tree[rt].left = left;
|
|
||||||
tree[rt].right = right;
|
|
||||||
tree[rt].date = a[left] % 38;
|
|
||||||
tree[rt].lan = 0;
|
|
||||||
tree[rt].lanc = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int mid = left + (right - left) / 2;
|
|
||||||
build(tree, a, rt * 2, left, mid);
|
|
||||||
build(tree, a, rt * 2 + 1, mid + 1, right);
|
|
||||||
tree[rt].left = left;
|
|
||||||
tree[rt].right = right;
|
|
||||||
tree[rt].lan = 0;
|
|
||||||
tree[rt].lanc = 1;
|
|
||||||
tree[rt].date = (tree[rt * 2].date + tree[rt * 2 + 1].date) % 38;
|
|
||||||
}
|
|
||||||
void lazycl(vector<node> &tree, int rt)
|
|
||||||
{
|
|
||||||
if(tree[rt].lan > 0 or tree[rt].lanc != 1)
|
|
||||||
{
|
|
||||||
int laz = tree[rt].lan / (tree[rt].right - tree[rt].left + 1);
|
|
||||||
tree[rt * 2].date += (laz * ((tree[rt * 2].right - tree[rt * 2].left) + 1)) % 38;
|
|
||||||
tree[rt * 2].lan += laz * ((tree[rt * 2].right - tree[rt * 2].left) + 1);
|
|
||||||
tree[rt * 2].date = (tree[rt * 2].date * tree[rt].lanc) % 38;
|
|
||||||
tree[rt * 2].lanc *= tree[rt].lanc;
|
|
||||||
tree[rt * 2 + 1].date += (laz * ((tree[rt * 2 + 1].right - tree[rt * 2 + 1].left) + 1)) % 38;
|
|
||||||
tree[rt * 2 + 1].lan += laz * ((tree[rt * 2 + 1].right - tree[rt * 2 + 1].left) + 1);
|
|
||||||
tree[rt * 2 + 1].date = (tree[rt * 2 + 1].date * tree[rt].lanc) % 38;
|
|
||||||
tree[rt * 2 + 1].lanc *= tree[rt].lanc;
|
|
||||||
tree[rt].lan = 0;
|
|
||||||
tree[rt].lanc = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void qjadd(vector<node> &tree, int rt, int add, int cl, int cr, int left, int right)
|
|
||||||
{
|
|
||||||
lazycl(tree,rt);
|
|
||||||
if(cl > right or cr < left)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(cl <= left and cr >= right)
|
|
||||||
{
|
|
||||||
tree[rt].date += (add * (tree[rt].right - tree[rt].left + 1)) % 38;
|
|
||||||
tree[rt].lan += add * (tree[rt].right - tree[rt].left + 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int mid = left + (right - left) / 2;
|
|
||||||
qjadd(tree, rt * 2, add, cl, cr, tree[rt].left, mid);
|
|
||||||
qjadd(tree, rt * 2 + 1, add, cl, cr, mid + 1, tree[rt].right);
|
|
||||||
tree[rt].date = (tree[rt * 2].date + tree[rt * 2 + 1].date) % 38;
|
|
||||||
}
|
|
||||||
void qjmul(vector<node> &tree, int rt, int mul, int cl, int cr, int left, int right)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(cl > right or cr < left)
|
|
||||||
{
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(cl <= left and cr >= right)
|
|
||||||
{
|
|
||||||
|
|
||||||
tree[rt].date *= (mul * tree[rt].lanc) % 38;
|
|
||||||
tree[rt].lanc = mul * tree[rt].lanc;
|
|
||||||
//cout << tree[rt].date << " [" << tree[rt].left << "," << tree[rt].right << "]" << tree[rt].lan << " " << tree[rt].lanc << endl;
|
|
||||||
return;
|
|
||||||
}lazycl(tree,rt);
|
|
||||||
int mid = left + (right - left) / 2;
|
|
||||||
qjmul(tree, rt * 2, mul, cl, cr, tree[rt].left, mid);
|
|
||||||
qjmul(tree, rt * 2 + 1, mul, cl, cr, mid + 1, tree[rt].right);
|
|
||||||
tree[rt].date = (tree[rt * 2].date + tree[rt * 2 + 1].date) % 38;
|
|
||||||
//cout << tree[rt].date << " [" << tree[rt].left << "," << tree[rt].right << "]" << tree[rt].lan << " " << tree[rt].lanc << endl;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
void qjcx(vector<node> &tree, int rt, int cl, int cr, int left, int right, int &sum)
|
|
||||||
{
|
|
||||||
lazycl(tree, rt);
|
|
||||||
|
|
||||||
if(cl > right or cr < left)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(cl <= left and cr >= right)
|
|
||||||
{
|
|
||||||
sum += tree[rt].date % 38;
|
|
||||||
//cout << tree[rt].date << " [" << tree[rt].left << "," << tree[rt].right << "]" << tree[rt].lan << " " << tree[rt].lanc << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mid = left + (right - left) / 2;
|
|
||||||
qjcx(tree, rt * 2, cl, cr, tree[rt].left, mid, sum);
|
|
||||||
qjcx(tree, rt * 2 + 1, cl, cr, mid + 1, tree[rt].right, sum);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
signed main()
|
|
||||||
{
|
|
||||||
ios::sync_with_stdio(false);
|
|
||||||
cin.tie(0);
|
|
||||||
cin >> n >> q >> m;
|
|
||||||
a.resize(n + 1);
|
|
||||||
tree.resize((n + 1) * 4);
|
|
||||||
for(int i = 1;i <= n; i++)
|
|
||||||
{
|
|
||||||
cin >> a[i];
|
|
||||||
}
|
|
||||||
build(tree, a, 1, 1, n);
|
|
||||||
// for(int i = 1;i <= n * 4; i++)
|
|
||||||
// {
|
|
||||||
// cout << tree[i].date << " [" << tree[i].left << "," << tree[i].right << "]" << tree[i].lan << " " << tree[i].lanc << endl;
|
|
||||||
// }
|
|
||||||
for(int i = 1;i <= q;i ++)
|
|
||||||
{
|
|
||||||
int c, x, y;
|
|
||||||
cin >> c >> x >> y;
|
|
||||||
if(c == 1)
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
cin >> k;
|
|
||||||
qjmul(tree, 1, k % 38, x, y, 1, n);
|
|
||||||
|
|
||||||
}
|
|
||||||
else if(c == 2)
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
cin >> k;
|
|
||||||
qjadd(tree, 1, k % 38, x, y, 1, n);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int sum = 0;
|
|
||||||
qjcx(tree, 1, x, y, 1, n, sum);
|
|
||||||
cout << sum % 38 << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user