[gmoj 3510] 【NOIP2013模拟11.5B组】最短路径

在这里插入图片描述
思路:
20分:
直接考虑用dfs暴搜完事
100分:
感性理解一下题目,从1~n再从 n1,转换一下就成了1n的两条不同路径之和最短的问题。
类似提高组2008年传纸条。
设f[i][j]为第一条路走到i号点,第二条路径走到第j号点的最短路径和。为了保证不出现两路相交的情况,即:f[i][i]。每次使用f[i][j]去更新max(i,j)+1,
所以动态转移方程为:
f [ 1 ] [ 1 ] = 0 ; k = m a x ( i , j ) + 1      d i s ( i , j ) 表 示 从 i 点 到 j 点 的 距 离 f[1][1] = 0; k = max(i, j) + 1 \;\;dis(i,j)表示从i点到j点的距离 f[1][1]=0;k=max(i,j)+1dis(i,j)ij
f [ k ] [ j ] = m a x ( f [ k ] [ j ] , f [ i ] [ j ] + d i s ( i , k ) ) f[k][j] = max(f[k][j], f[i][j] + dis(i,k)) f[k][j]=max(f[k][j],f[i][j]+dis(i,k))
f [ i ] [ k ] = m a x ( f [ i ] [ k ] , f [ i ] [ j ] + d i s ( j , k ) ) f[i][k] = max(f[i][k], f[i][j] + dis(j, k)) f[i][k]=max(f[i][k],f[i][j]+dis(j,k))
对于b1,b2和k - 1 == n的情况,我们只需要将点强制转换到特殊点即上述三点上。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;

const int N = 1e3 + 10;
int n, b1, b2;
double f[N][N], x[N], y[N];

double d(int a, int b) {return sqrt((x[a] - x[b]) * (x[a] - x[b]) * 1.0 + (y[a] - y[b]) * (y[a] - y[b]) * 1.0);}

int main()
{
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
	scanf("%d%d%d", &n, &b1, &b2);
	for(int i = 1; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]);
	memset(f, 0x7f, sizeof(f));
	f[1][1] = 0;
	for(int i = 1; i <= n; i++)
	 for(int j = 1; j <= n; j++)
	 {
		if(i == j && i != 1) continue;
		int k = max(i, j) + 1;
		if(k > n)
		{
			if(i < n) f[n][n] = min(f[n][n], f[i][j] + d(i, n));
			if(j < n) f[n][n] = min(f[n][n], f[i][j] + d(j, n));
		}
		else
		{
			if(k != b2 + 1) f[k][j] = min(f[k][j], f[i][j] + d(i, k));
			if(k != b1 + 1) f[i][k] = min(f[i][k], f[i][j] + d(j, k));
		}
	 }
	printf("%.2lf\n", f[n][n]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值