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,因此单独列一条语句进行赋值