[POI2005]PRA-Dextrogyrate Camel DP计算几何

Posted cjTQX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POI2005]PRA-Dextrogyrate Camel DP计算几何相关的知识,希望对你有一定的参考价值。

洛谷P3433

Description

平面上有 \\(n\\) 个点 \\((x_i,y_i)\\)。小 \\(L\\)\\(1\\) 号点出发,面向 \\(2\\) 号点以直线前进。每到达一个点,小 \\(L\\) 就可以让前进方向顺时针旋转 \\([0,180)\\) 度,并向下一个点以直线前进,最终回到 \\(1\\) 号店。要求在整个行进过程中路径不相交(不包括顶点处),不重复经过 \\(1\\) 号点外的点,到达 \\(1\\) 号点后立即结束,请问小 \\(L\\) 最多能一次经过多少个节点?数据保证无三点共线。

\\(n\\le 2000,|x_i|,|y_i|\\le 16000\\)

Solution

首先平移坐标系,使 \\(1\\) 号点为原点。

考虑什么样的路径是合法的:(此处借用了这位大佬题解中的图片)

图中的蓝色点为 \\(1\\) 号点,红色与绿色为其他点,当选择了某个红色点时,其上方的所有红色点都无法再走到了;同样的,选择了某个绿色点时,其下方的所有绿色点也无法走到了。

因此,将 \\(1\\) 号点外的点极角排序,那么最优选择一定时从 \\(2\\) 号点开始沿顺时针方向走(此时合法的目标点一定再顺时针方向)。因此可以极角排序后,将 \\(2\\) 号点排在首位,其他点按顺时针方向依次加入。设 \\(dp_{i,j}\\) 表示现在走到了第 \\(i\\) 个点,上一个走到的点位 \\(j\\) 号点时的最长路径。然后 \\(\\mathcal O(n)\\) 枚举下一个转移点并判断能否到达。状态是 \\(\\mathcal O(n^2)\\) 的,因此总复杂度位 \\(\\mathcal O(n^3)\\)

考虑优化,将 \\(dp_{i,j}\\) 改为走到了第 \\(i\\) 个点,经过了 \\(\\ge j\\) 个点时能使得可选择后继范围最大的前驱。那么转移时,枚举当前点 \\(i\\) 以及前驱 \\(j\\),即可二分找到能够从 \\(j\\) 到达 \\(i\\) 的前提下,经过的路径最大是多少,如果二分出的答案是 \\(k\\),就可以用 \\(dp_{j,k}\\) 更新 \\(dp_{i,k+1}\\)。更新完之后,再对与每个 \\(i\\) ,将 \\(j\\) 从大到小扫一遍,用 \\(dp_{i,j}\\) 更新 \\(dp_{i,j-1}\\) 选择可选后继范围更大的一个前驱。判断谁的可选范围最大可以使用叉积完成。

最终复杂度优化到 \\(\\mathcal O(n^2\\log n)\\)

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2010;
const double pi=acos(-1.0);
int n,pos[N],dp[N][N];
double ang[N];
struct pt{
	int x,y;
	pt(int _x=0,int _y=0){x=_x;y=_y;}
}p[N];
inline ll operator ^(const pt& a,const pt& b){return 1ll*a.x*b.y-1ll*a.y*b.x;}
inline pt operator -(const pt& a,const pt& b){return pt(a.x-b.x,a.y-b.y);}
inline bool cmp(int x,int y){return ang[x]<ang[y];}
inline bool check(int i,int j,int k){return ((p[pos[j]]-p[pos[i]])^(p[pos[k]]-p[pos[j]]))<0;}
inline void upd(int pos,int &x,int y){
	if(x==-1){x=y;return ;}
	(check(pos,y,x))&&(x=y);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d%d",&p[i].x,&p[i].y);
	for(int i=2;i<=n;++i) p[i]=p[i]-p[1];p[1]=p[1]-p[1];
	for(int i=0;i<n;++i) pos[i]=i+1,ang[i+1]=atan2(p[i+1].y,p[i+1].x);
	double tmp=ang[2];
	for(int i=2;i<=n;++i){
		ang[i]=tmp-ang[i];
		ang[i]=fmod(ang[i]+6*pi,2*pi);
	}
	sort(pos+1,pos+n,cmp);
	memset(dp,-1,sizeof(dp));
	dp[1][1]=0;
	int ans=1;
	for(int i=2;i<n;++i){
		for(int j=1;j<i;++j){
			if(check(j,i,0)){
				int l=1,r=j,ret=-1;
				while(l<=r){
					int mid=(l+r)>>1;
					if((~dp[j][mid])&&check(dp[j][mid],j,i)) l=mid+1,ret=mid;
					else r=mid-1;
				}
				if(~ret) upd(i,dp[i][ret+1],j),ans=max(ans,ret+1);
			}
		}
		for(int j=i-1;~j;--j) if(~dp[i][j+1]) upd(i,dp[i][j],dp[i][j+1]);
	}
	printf("%d\\n",ans);
	return 0;
}

以上是关于[POI2005]PRA-Dextrogyrate Camel DP计算几何的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ1537][POI2005]Aut- The Bus

[POI2005]SAM-Toy Cars

[Luogu3425][POI2005]KOS-Dicing

P3420 [POI2005]SKA-Piggy Banks

Bzoj 1537: [POI2005]Aut- The Bus 题解 [由暴力到正解]

BZOJ 1531 POI2005 Bank notes