洛谷 P1523 旅行商简化版(DP)

题目链接

https://www.luogu.com.cn/problem/P1523

思路

我们可以将问题转化成两个人从同一个位置出发,走不同的路,最后到达相同终点的最短路径。

d p [ i ] [ j ] dp[i][j] dp[i][j]表示一个人走到第 i i i个点,另一个人走到第 j j j个点( i > j i > j i>j),且 [ 1 , i ] [1,i] [1,i]的所有点都已经被走过的最短路。

i = = j + 1 i == j + 1 i==j+1时,其中一个人可以从第 k k k个点走到第 i i i个点, d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ j ] [ k ] + D i s t a n c e ( p [ k ] , p [ i ] ) ) dp[i][j] = min(dp[i][j], dp[j][k] + Distance(p[k], p[i])) dp[i][j]=min(dp[i][j],dp[j][k]+Distance(p[k],p[i])),其中 k ∈ [ 1 , j ) k \in [1,j) k[1,j)

i > j + 1 i > j+1 i>j+1时,第一个人走的上一个点只能是第 i i i个点,所以: d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i − 1 ] [ j ] + D i s t a n c e ( p [ i − 1 ] , p [ i ] ) ) dp[i][j] = min(dp[i][j], dp[i - 1][j] + Distance(p[i - 1], p[i])) dp[i][j]=min(dp[i][j],dp[i1][j]+Distance(p[i1],p[i]))

代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double

typedef long long i64;
typedef unsigned long long u64;
typedef pair<int, int> pii;

const int N = 1e3 + 5, M = 2e2 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;

std::mt19937 rnd(time(0));

int n;
double dp[N][N];
struct Point
{
	int x, y;
	Point() {}
	Point(int x, int y): x(x), y(y) {}
	bool operator<(const Point&other) {
		if (x != other.x)
			return x < other.x;
		return y < other.y;
	}
} p[N];
double Distance(Point A, Point B)
{
	return sqrtl((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
void solve(int test_case)
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> p[i].x >> p[i].y;
	}
	sort(p + 1, p + 1 + n);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			dp[i][j] = inf;
		}
	}
	dp[2][1] = Distance(p[2], p[1]);
	for (int i = 3; i <= n; i++)
	{
		for (int j = i - 1; j >= 1; j--)
		{
			if (i == j + 1)
			{
				for (int k = j - 1; k >= 1; k--)
				{
					dp[i][j] = min(dp[i][j], dp[j][k] + Distance(p[k], p[i]));
				}
			}
			else
			{
				dp[i][j] = min(dp[i][j], dp[i - 1][j] + Distance(p[i - 1], p[i]));
			}
		}
	}
	double ans = inf;
	for (int i = 1; i < n; i++)
	{
		ans = min(ans, dp[n][i] + Distance(p[i], p[n]));
	}
	cout << fixed << setprecision(2) << ans << endl;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int test = 1;
	// cin >> test;
	for (int i = 1; i <= test; i++)
	{
		solve(i);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值