题意
给定
解析
先说解法:将所有边按照 atan2(y,x)
的值排序, 然后枚举凸多边形起点,再遍历排序后的边进行 dp 转移,复杂度为
大致思路与已有题解相同,但是我在这里想要阐述一个困惑我许久的点:为什么是 atan2
?
搜索百度百科可以发现,atan2
这个函数的返回值是方位角(而 atan
返回的仅是数字的反正切值),具体地:
然后我们来看一个凸多边形。
我们可以将这个凸多边形分为四部分,在图中分别用四种颜色表示。
对于蓝色部分:满足
对于橙色部分:满足
对于黄色部分:满足
对于灰色部分:满足
我们可以发现,atan2(y,x)
的值是单调递增的,最后回到这个点,形成的图形就一定是一个凸多边形。
因此,我们只需要枚举这个起始点,然后遍历排序好的边进行 dp,最后用这个起始点上的结果来更新答案就可以了,详见代码。
代码
#include<bits/stdc++.h> using namespace std; const int N=255; int n,cnt,ans; int f[N]; struct P{ int u,v,x,y; }a[N],e[N*N]; inline bool cmp(P i,P j){//按照 atan2 的值排序 return atan2(i.y,i.x)<atan2(j.y,j.x); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); for(int i=1;i<=n;i++)//连边 for(int j=1;j<=n;j++){ if(i==j) continue; e[++cnt].u=i,e[cnt].v=j; e[cnt].x=a[j].x-a[i].x,e[cnt].y=a[j].y-a[i].y; } sort(e+1,e+1+cnt,cmp); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) f[j]=-1e9+7; f[i]=0;//枚举起始点 for(int j=1;j<=cnt;j++) f[e[j].v]=max(f[e[j].v],f[e[j].u]+1);//动规 ans=max(ans,f[i]);//更新答案 } printf("%d\n",ans); return 0; }