【题解】CF30D King's Problem?
CF30D
题意
有 \(n+1\) 个点,其中的 \(n\) 个点在数轴上。求以点 \(k\) 为起点走过所有点的最短距离,允许重复。
思路
有两种情况:
- \(k\) 在数轴上(如图1)。
- \(k\) 在第 \(n+1\) 个点上(如图2)。
图1:

图2:

像第一种情况:
一定存在数轴上某点 \(k\) ,使得人先走遍 \(1\sim k\) ,回来,再走遍 \(k + 1\sim n\) ;
或点 \(k\) ,使得人先走遍 \(k + 1\sim n\) ,回来,再走遍 \(1\sim k\)
从点 \(p\) 出发,走一个区间 \(\left [ l,r \right ]\) 。
最短方案显然是从 \(p\) 到 \(l\) 或 \(r\) 中较近的一个,然后一路走到对面。 距离是\(dist (a_l ,a_r ) + \min(dist(p,a_l ),dist(p,a_r ))\) 。
从点 \(k\) 出发,走一个区间 \([l ,r]\) ,再回到 \(p\) 。最佳方案可以证明是从 \(k\) 走到 \(l\) 或 \(r\) 中的某一个,然后走到对面,然后走到 \(p\) 。距离是 \(|a_l-a_r| + \min(|a_k-a_l| +dist(r),| a_k-a_r | +dist(l))\) 。
AC Code
#include<bits/stdc++.h>
using namespace std;
int k,i,j,n;
double ans,x[100010],xp,yp,xk;
double C(int z) {
	return hypot(a[z]-xp,yp);//hypot勾股定理 
}
double A(int l,int r) {
	return a[r]-a[l]+min(C(l),C(r)); 
}
double B(int l,int r) {
	return a[r]-a[l]+min(abs(xk-a[l])+C(r),abs(xk-a[r])+C(l)); 
}
int main() {
	cin>>n>>k;
	for (i=1; i<=n; i++) cin>>a[i];
	cin>>xp>>yp;
	xk=a[k];
	sort(a+1,a+n+1);
	if (k<=n) {
		ans=B(1,n);
		for (i=2; i<=n; i++) {
			double t=min(A(1,i-1)+B(i,n),A(i,n)+B(1,i-1));
			if (t<ans) ans=t;
		}
		printf("%.20lf\n",ans);
	} else printf("%.20lf\n",A(1,n));
	return 0;
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号