zoukankan      html  css  js  c++  java
  • BZOJ1591 & 洛谷2924:[USACO2008 DEC]Largest Fence 最大的围栏——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1591

    https://www.luogu.org/problemnew/show/P2924#sub

    有n(5≤n≤250)个栅栏点,FJ需要围成一个栅栏圈,这个圈是一个凸包并且凸包上的点最多。

    这题题解写的如此之玄幻,题目看起来如此之不可做……

    然而实际很简单……看了半天题解发现不如看他代码。

    我们考虑我们是怎么构造凸包的,就是通过点的极角排序来判断这个点所引出的线应该往哪里转(或者可能不取这个点)……

    那么我们显然可以对边进行极角排序,然后利用这些边来构造凸包。

    首先我们枚举点a作为这个凸包的最左点,dp[i][j]表示(i,j)这条边作为凸包a的最后一条边时一共有多少点。

    那么我们枚举k,显然如果满足极角排序中(k,i)<(i,j)那么(k,i)(i,j)就可以作为这个凸包的两条边,我们就可以dp[i][j]=max{dp[k][i]+1}

    但是显然是O(n^4)的,考虑优化。

    如果我们可以求出g[i]=max{dp[k][i]}显然可以O(n^2)。

    于是对所有的边进行极角排序,枚举排序后的边端点x,y有g[y]=max(g[y],g[x]+1)(显然,可感性理解,初值g[a]=0,其余为-INF),同时转移dp即可。

    #include<cstdio>
    #include<queue>
    #include<cctype>
    #include<cstring>
    #include<stack>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=260;
    const int INF=2147483647;
    struct point{
        int x,y;
    }p[N],q[N];
    struct line{
        point v;
        int x,y;
    }v[N*N];
    int n,cnt,per[N],l,g[N],dp[N][N];
    inline point getmag(point a,point b){
        point s;
        s.x=b.x-a.x;s.y=b.y-a.y;
        return s;
    }
    inline int multiX(point a,point b){
        return a.x*b.y-b.x*a.y;
    }
    inline bool cmp(line a,line b){
        return multiX(a.v,b.v)<0;
    }
    inline void init(){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)g[i]=-INF;
    }
    int solve(){
        int ans=0;
        for(int i=1;i<=n;i++){
            init();
            g[i]=0;
            for(int j=1;j<=cnt;j++){
                int px=v[j].x,py=v[j].y;
                dp[px][py]=max(dp[px][py],g[px]+1);
                if(py!=i)g[py]=max(g[py],g[px]+1);
            }
            for(int j=1;j<=n;j++)ans=max(ans,dp[j][i]);
        }
        return ans;
    }
    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){
                    v[++cnt].x=i;
                    v[cnt].y=j;
                    v[cnt].v=getmag(p[i],p[j]);
                }
            }
        }
        sort(v+1,v+cnt+1,cmp);
        printf("%d
    ",solve());
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    
    

    +本文作者:luyouqi233。               +

    
    

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    
    

    +++++++++++++++++++++++++++++++++++++++++++

     
  • 相关阅读:
    php 创建多级文件夹
    php 格式化文件大小
    php 微信授权登录
    获取单据编号 不重复 骚
    js获取数组中的最后一个
    php截取
    循序栈
    链表
    顺序表
    halcon学习之阈值算子threshold operators
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8394763.html
Copyright © 2011-2022 走看看