ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[cf1599G]Shortest path

2021-10-23 09:33:55  阅读:173  来源: 互联网

标签:cf1599G Point int 共线 访问 path include Shortest dis


题意:给n个点,其中n-1个共线,指定一个起点,每次可从一个点沿直线移动至另一个点,点可重复访问,问访问过所有点至少一次的最短路径。

首先我们肯定要找出不共线的那个点。按x坐标将n个点排序,计算出所有相邻两点的斜率,只要点数大于等于四,那么和其它不同的两个斜率之间的点就是不共线的点。(仅有三个点的情况直接算一下就好。)为了方便起见,我们可以重新排个序,将不共线点放到最后,1到n-1为有序的共线点。

显然,如果没有不共线点,那么我们肯定始终沿直线移动,故不共线点仅会被访问一次。以及,进行多次折回显然无意义,在除端点外的所有位置不应进行多于一次折回。

故对于起点不是不共线点的情况,我们相当于将共线点分成连续的两端——经过不共线点之前访问和之后访问。首先枚举K≤i<n-1,ans1 = min( dis(K,i) + dis(i,1) + dis(1,n) + dis(n,i+1) + dis(i+1,n-1), dis(k,1) + dis(1,i) + dis(i,n) + dis(n,i+1) + dis(i+1,n-1) ); 同理1<i≤K, ans2 = min( dis(K,i) + dis(i,n-1) + dis(n-1,n) + dis(n,i-1) + dis(i-1,1), dis(k,n-1) + dis(n-1,i) + dis(i,n) + dis(n,i-1) + dis(i-1,1) )。最终答案是min(ans1, ans2),再单独计算一下i=1或n-1的情况,一起取个最小值。

如果起点就是不共线点,那么很简单,答案就是dis(1,n−1) + min(dis(1, n), dis(n−1, n)).

一开始自己写的时候没考虑全情况……

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int N=200010;
const double eps=1e-10;
struct Point{
	int x,y,id,rnk;
}p1[N];
int n,m,s,p;
bool ok[N];
double ans,tot;
bool cmp(Point i,Point j){
	if(i.x!=j.x)return i.x<j.x;
	return i.y<j.y;
}
bool cmp1(Point i,Point j){
	return i.rnk<j.rnk;
}
inline bool check(Point i,Point j,Point k){
	return 1ll*(j.x-i.x)*(k.y-j.y)==1ll*(k.x-j.x)*(j.y-i.y);
}
inline double dis(int i,int j){
	return sqrt(1.0*(p1[i].x-p1[j].x)*(p1[i].x-p1[j].x)+1.0*(p1[i].y-p1[j].y)*(p1[i].y-p1[j].y));
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d%d",&p1[i].x,&p1[i].y),p1[i].id=i;
	if(n==3){
		double tmp[3];
		ans=dis(1,2)+dis(2,3)+dis(3,1);
		for(int i=1,j=0;i<=3;++i){
			if(i!=m)tmp[++j]=dis(i,m);
		}
		ans-=max(tmp[1],tmp[2]);
		printf("%lf\n",ans);
		return 0;
	}
	sort(p1+1,p1+n+1,cmp);
	for(int i=1;i<=n;++i)p1[i].rnk=i;
	p=0;
	for(int i=2;i<n;++i)
		ok[i]=check(p1[i-1],p1[i],p1[i+1]);
	for(int i=2;i<n;++i)
		if(!ok[i-1]&&!ok[i]&&!ok[i+1])p=i;
	if(!p&&!ok[2])p=1;
	else if(!p) p=n;
	p1[p].rnk=n+1;
	sort(p1+1,p1+n+1,cmp1);
	for(int i=1;i<=n;++i)if(p1[i].id==m)s=i;
	if(s!=n){
		ans=min(dis(s,n-1)+dis(n-1,1)+dis(1,n),dis(s,1)+dis(1,n-1)+dis(n-1,n));
		for(int i=s;i<n-1;++i){
			tot=min(dis(s,i)+dis(i,1)+dis(1,n)+dis(n,i+1)+dis(i+1,n-1),dis(s,1)+dis(1,i)+dis(i,n)+dis(n,i+1)+dis(i+1,n-1));
			ans=min(ans,tot);
		}
		for(int i=2;i<=s;++i){
			tot=min(dis(s,i)+dis(n-1,i)+dis(n-1,n)+dis(n,i-1)+dis(i-1,1),dis(s,n-1)+dis(n-1,i)+dis(i,n)+dis(n,i-1)+dis(i-1,1));
			ans=min(ans,tot);
		}
	}else ans=dis(1,n-1)+min(dis(1,n),dis(n-1,n));
	printf("%lf\n",ans);
	return 0;
} 

标签:cf1599G,Point,int,共线,访问,path,include,Shortest,dis
来源: https://blog.csdn.net/xfy_tjjyzhu/article/details/120916539

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有