codevs1273 风战 【三角剖分+凸包+动态规划】

题目大意:

原题翻译细节有误,加上我自己看丢条件,导致我想了半天没想通。
题意是有n个白点,m个黑点,还有原点(0,0)无色,黑白点的纵坐标均大于0,且无三点共线,要求一个必须包含原点的凸包,使得凸包中白点的数量减黑点的最多。n+m小等于100。

解题思路:

如果没有“纵坐标均大于0”,“无三点共线“,“必须包含原点”三个条件,题目将变得很恶心,然而原题没翻译第三个条件,我看丢了前两个……

这样就好做了,直接 O(n3) O ( n 3 ) 三角剖分出每两个点与原点组成三角形内部点值,f[i][j]表示i点从j点转移来的最优值,dp下一个点时直接判该点是否是在直线ji左侧即可转移(就是满足凸包性质),dp复杂度也是 O(n3) O ( n 3 )

不过这两步都可以有平衡树维护到 O(n2log2n) O ( n 2 l o g 2 n ) ,可以参考这里

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=105;
struct point
{
    int x,y,t;
    point(){}
    point(int _x,int _y):x(_x),y(_y){}
    inline friend point operator - (const point &a,const point &b)
    {return point(a.x-b.x,a.y-b.y);}
    inline friend ll operator * (const point &a,const point &b)
    {return 1ll*a.x*b.y-1ll*a.y*b.x;}
    inline friend bool operator < (const point &a,const point &b)
    {return atan2(a.y,a.x)<atan2(b.y,b.x);}
}p[N];
int n,m,ans,g[N][N],f[N][N];

int main()
{
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)p[i].x=getint(),p[i].y=getint(),p[i].t=1;
    for(int i=n+1;i<=n+m;i++)p[i].x=getint(),p[i].y=getint(),p[i].t=-1;
    n+=m;sort(p+1,p+n+1);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int k=i+1;k<j;k++)
                if((p[i]-p[k])*(p[j]-p[k])>0)
                    g[i][j]+=p[k].t;
    for(int i=1;i<=n;i++)
    {
        f[i][0]=p[i].t;
        for(int j=1;j<i;j++)
            for(int k=0;k<j;k++)
                if((p[k]-p[i])*(p[j]-p[i])>=0)
                    f[i][j]=max(f[i][j],f[j][k]+g[j][i]+p[i].t);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            ans=max(ans,f[i][j]);
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值