[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
[Luogu3425][POI2005]KOS-Dicing
P3420 [POI2005]SKA-Piggy Banks