卧薪尝胆,厚积薄发。
USACO2008DEC GOLD Largest Fence 最大的围栏
Date: Mon Dec 10 14:57:59 CST 2018 In Category: NoCategory

Description:

有 $n$ 个栅栏点,围成一个栅栏圈,这个圈是一个凸包并且凸包上的点最多。
$5\leqslant n\leqslant 250$

Solution:

凸包的性质是周围的直线斜率单调,也就是说如果我们按照斜率单调的顺序依次转移所有点间的直线的话最后形成的一定是一个凸包,于是我们只要把所有点之间的连线拿出来,然后像半平面交那样极角排序,然后枚举每个点作为第一个点,然后 $DP$ 就可以了,最后再用这个第一个点的 $DP$ 值更新答案,因为是循环的,这样显然不会丢掉最优解。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n;
#define MAXN 251
struct point
{
int x,y;
}p[MAXN];
double slope(point p1,point p2){return 1.0 * (p2.y - p1.y) / (p2.x - p1.x);}
struct line
{
int p1,p2;double k;
}l[MAXN * MAXN];
int tot = 0;
bool cmp_k(line a,line b){return a.k < b.k;}
int f[MAXN];
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)
{
scanf("%d%d",&p[i].x,&p[i].y);
}
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= n;++j)
{
if(i == j)continue;
l[++tot] = (line){i,j,atan2(p[j].y - p[i].y,p[j].x - p[i].x)};
}
}
sort(l + 1,l + 1 + tot,cmp_k);
int ans = 0;
for(int i = 1;i <= n;++i)
{
memset(f,0xc0,sizeof(f));
f[i] = 0;
for(int k = 1;k <= tot;++k)
{
f[l[k].p2] = max(f[l[k].p2],f[l[k].p1] + 1);
}
ans = max(ans,f[i]);
}
cout << ans << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡