遗迹探险(DP)

D-遗迹探险_牛客小白月赛72 (nowcoder.com)

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

小Z是一名探险家。有一天,小Z误入了一个魔法遗迹。以下是该遗迹的具体组成:

1. 在 xxx 轴和 yyy 轴构成的平面上,满足在 1≤x≤n1 \le x \le n1≤x≤n,1≤y≤m1 \le y \le m1≤y≤m 的区域中(坐标(x,y)(x, y)(x,y)表示平面上的第xxx行的第yyy列),每个整数坐标 (x,y)(x,y)(x,y) 都有一个宝藏,坐标为(i,j)(i,j)(i,j)的宝藏的价值为ai,ja_{i,j}ai,j​(请注意,宝藏的价值可以为负)。换句话说,这个区域上的整点都有一个宝藏。
2. 对于任意一对点 (x1,y1)(x_1, y_1)(x1​,y1​) 和 (x2,y2)(x_2, y_2)(x2​,y2​),如果它们的横坐标相等,纵坐标之差为 111,则纵坐标小的点有一条道路可以到达纵坐标大的点,或者它们的纵坐标相等,横坐标之差为 111,则横坐标小的点有一条道路可以到达横坐标大的点。换句话说,(x,y)(x,y)(x,y)可以到达(x+1,y)(x+1 ,y)(x+1,y)或(x,y+1)(x,y+1)(x,y+1),反之不然。
3. 遗迹的入口在(1,1)(1,1)(1,1),出口在(n,m)(n,m)(n,m),小Z从入口进入后从出口离开,在移动的过程中他会将他所遇到的所有宝藏全部收集起来。


小Z想知道从进入到离开遗迹,他在离开遗迹时所能获得的宝藏的价值的和最大为多少

作为一个有智慧的探险家,小Z当然会解决这个问题。但是由于这个遗迹具有魔法,问题就变得不是那么简单了。

在小Z进入该遗迹前,遗迹的魔法发动,它会在若干个具有宝藏的位置生成一个传送门。若小Z所在的坐标有传送门,则他可以通过这个传送门到达其它任意一个具有传送门的位置(当然,他也可以选择不使用传送门),并且小Z在使用一次传送门后,所有的传送门都会消失。换句话说,小Z只能最多使用一次传送门。

该遗迹具有魔法,每当小Z离开某个整点,该整点就会重新生成一个价值为ai,ja_{i,j}ai,j​的宝藏。

小Z会进入TTT次该遗迹。请你帮助小Z计算出,对于每次进入遗迹,在给定传送门的坐标的情况下,他在离开遗迹时所能获得的宝藏的价值的和最大为多少

AC代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxn = 1e3 + 10;
int dp1[maxn][maxn], dp2[maxn][maxn], N, M, K, MAP[maxn][maxn], T, A, B, ans;
void Init()
{
    cin >> N >> M;
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= M; j++)
            cin >> MAP[i][j];
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= M; j++)
            if(1 == i)dp1[i][j] = dp1[i][j - 1] + MAP[i][j];
            else if(1 == j)dp1[i][j] = dp1[i - 1][j] + MAP[i][j];
            else dp1[i][j] = MAP[i][j] + max(dp1[i - 1][j], dp1[i][j - 1]);
    for (int i = N; i >= 1; i--)
        for (int j = M; j >= 1; j--)
            if(N == i)dp2[i][j] = dp2[i][j + 1] + MAP[i][j];
            else if(M == j)dp2[i][j] = dp2[i + 1][j] + MAP[i][j];
            else dp2[i][j] = MAP[i][j] + max(dp2[i + 1][j], dp2[i][j + 1]);
}
void sove()
{
    ans = dp1[N][M];
    cin >> K;
    vector<pair<int, int>>v;
    while (K--)
    {
        cin >> A >> B;
        v.emplace_back(A, B);
    }
    for (int i = 0; i < v.size(); i++)
        for (int j = 0; j < v.size(); j++)
        {
            if (i == j)continue;
            ans = max(ans, dp1[v[i].first][v[i].second] + dp2[v[j].first][v[j].second]);
        }
    cout << ans << endl;
}
signed main()
{
    IOS
    Init();
    cin >> T;
    while (T--)
        sove();
    return 0;
}

俩个基础的dp数组,分别为dp1代表从1,1开始到[i,j]的最大宝藏价值以及dp2代表[i,j]到[N,M]的最大宝藏价值.

疑惑点

 for (int i = 1; i <= N; i++)
        for (int j = 1; j <= M; j++)
            if(1 == i)dp1[i][j] = dp1[i][j - 1] + MAP[i][j];
            else if(1 == j)dp1[i][j] = dp1[i - 1][j] + MAP[i][j];
            else dp1[i][j] = MAP[i][j] + max(dp1[i - 1][j], dp1[i][j - 1]);
    for (int i = N; i >= 1; i--)
        for (int j = M; j >= 1; j--)
            if(N == i)dp2[i][j] = dp2[i][j + 1] + MAP[i][j];
            else if(M == j)dp2[i][j] = dp2[i + 1][j] + MAP[i][j];
            else dp2[i][j] = MAP[i][j] + max(dp2[i + 1][j], dp2[i][j + 1]);

为什么对于dp1和dp2的[i j]在边界条件时,要单独使用if语句?

我们知道当i j为边界时,迷宫走法是单调的,要么只能往右,要么只能往下由于我们[i,j]为0以及[i,j]大于N,M时,其他数组内值均为0,但是由于 宝藏的价值可以为负,避免当边界值为负数的我们取最大反而变成0,因此单独列一条语句进行赋值

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值