您的位置:首页 > Web前端

Bzoj1591:[Usaco2008 Dec]Largest Fence 最大的围栏:DP

2016-04-05 16:15 441 查看
题目链接:1591:[Usaco2008 Dec]Largest Fence 最大的围栏

显然不能枚举

考虑dp,每个点肯定都有一个包含他的最大的凸包

观察凸包,存在一条边使得顺时针看凸包上一圈的边极角是递增的,手画一个凸包就可以发现(三象限->四->一->二)

别告诉我你不知道极角是会有负数的

所以我们将点两两连边,将边按照极角排序

设f[i]为包含i的最大凸包上的点的数量,则f[j]=max(f[j],f[i]+1)(i->j有边)

凸包是一个环,边的极角序递增,我们做dp必然会转移到i,最终f[i]就是包含i的最大凸包上的点的数量

初值f[i]=0,剩下的点赋值为极小值,由于是按极角排的序,极角小的边先被更新,所以只要按照拍完序的边进行转移就会得到正确的转移顺序

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=310;
struct Line{
int u,v; double a;
}l[maxn*maxn];
struct point{
int x,y;
}p[maxn];
bool cmp(const Line &a,const Line &b){
return a.a<b.a;
}
int f[maxn],n,N=0,ans=0;

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){
N++; l
.u=i; l
.v=j;
l
.a=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
}
sort(l+1,l+N+1,cmp);
for (int i=1;i<=n;++i){
for (int j=1;j<=n;++j) f[j]=-0x7fffffff;
f[i]=0;
for (int j=1;j<=N;++j)
f[l[j].v]=max(f[l[j].v],f[l[j].u]+1);
ans=max(ans,f[i]);
}
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息