牛客网 C张老师的旅行 三维区间DP

链接:链接
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
张老师到了一个王国去旅游,王国有n个景点,张老师到达这个城市所在的车站恰好位于第x个景点,这个王国非常特别,恰好所有著名的景点都在分布在直线上,每个景点在坐标pi上(单位:公里),张老师身体非常好,每走一公里花费一分钟。每个景点都有一个打卡点,并且必须在不迟于相应的时间(时间从张老师到达王国开始计算)前到达才能打卡成功并且给以一个打卡标记,集齐所这些标记就能获得一个大礼包。由于张老师非常想要大礼包,并且因为张老师还着急去下一个王国旅游,所以张老师希望用的时间尽量少,你能帮帮张老师吗?

输入描述: 输入的第一行,包含一个整数n(1≤n≤1000)。
第二行包含n个整数pi(1≤pi≤100000),第i个整数pi为第i个景点的坐标(坐标从小到大排列)。
最后一行包含n个整数ti(0≤ti≤10,000,000),ti表示第i个景点最迟到达的时间,时间为0则表示张老师所在车站的位置且只有一个为0。

输出描述: 输出所需的最少时间,若无解输出-1。

这题很明显 最后一步一定是从1 -> N 或者从N -> 1
设dp[l][r][k]
if(k == 0)
dp[l][r][k]的意义是从走完 [l, r] 的区间停留在 l 点的花费最小值
if(k == 1)
dp[l][r][k]的意义是从走完 [l, r] 的区间停留在 r 点的花费最小值

dp[_index][_index] = 0; //起始点
区间DP

那么就很好理解
符合要求的条件下
dp[l][r][0] 可以从 dp[l + 1][r][0] 和 dp[l + 1][r][1]转移可得
对应的
dp[l][r][1] 可以从 dp[l][r - 1][0] 和 dp[l][r - 1][1]转移可得

然后枚举l, r就可以了 很简单了 就是一个三维区间DP

//MADE BY Y_is_sunshine;
//#include <bits/stdc++.h>
//#include <memory.h>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>

#define pb push_back
#define pf push_front
#define INF 0x3f3f3f3f
#define MAXN (int) 1e3 + 7
#define all(a) a.begin(), a.end()

typedef long long ll;

const ll mod = 1e9 + 7;
const double PI = acos(-1);

using namespace std;

int N, M, K, T;

int d[MAXN];
int ti[MAXN];

int dp[MAXN][MAXN][2];

signed main(void) {

#ifdef Sunshine
	freopen("data.txt", "r", stdin);
#endif

	ios_base::sync_with_stdio(false);
	cin.tie(NULL);

	cin >> N;
	for (int i = 1; i <= N; i++)
		cin >> d[i];

	int _index;
	for (int i = 1; i <= N; i++) {
		cin >> ti[i];
		if (!ti[i])
			_index = i;
	}

	memset(dp, 0x3f, sizeof(dp));

	dp[_index][_index][0] = dp[_index][_index][1] = 0;

	for (int len = 1; len < N; len++) {
		for (int i = 1; i + len <= N; i++) {
			int j = i + len;
			
			if (dp[i + 1][j][0] + d[i + 1] - d[i] <= ti[i])
				dp[i][j][0] = min(dp[i][j][0], dp[i + 1][j][0] + d[i + 1] - d[i]);
			if (dp[i + 1][j][1] + d[j] - d[i] <= ti[i])
				dp[i][j][0] = min(dp[i][j][0], dp[i + 1][j][1] + d[j] - d[i]);
			if (dp[i][j - 1][1] + d[j] - d[j - 1] <= ti[j])
				dp[i][j][1] = min(dp[i][j][1], dp[i][j - 1][1] + d[j] - d[j - 1]);
			if (dp[i][j - 1][0] + d[j] - d[i] <= ti[j])
				dp[i][j][1] = min(dp[i][j][1], dp[i][j - 1][0] + d[j] - d[i]);

		}
	}


	int _min = min(dp[1][N][0], dp[1][N][1]);

	if (_min == INF)
		cout << -1 << '\n';
	else
		cout << _min << '\n';










#ifdef Sunshine
	freopen("CON", "r", stdin);
	system("pause");
#endif
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值