首页 > 其他 > 详细

2019年华南理工大学程序设计竞赛(春季赛) 单身狗救星 (凸包+二分)

时间:2019-04-16 18:14:03      阅读:151      评论:0      收藏:0      [点我收藏+]

https://ac.nowcoder.com/acm/contest/625/J

题目:有n个男的 , m 个女的 ,女生去选择男生为好丽友 , 选择的好丽友的价值为 (y1-y2) / (x1-x2) ; 

问女生选了哪些男生 , 如果有多个男生价值相同选择编号最小的

 

分析:看到价值 是(y1-y2) / (x1-x2) 的形式 , 多么容易想到是凸包哦 , (其实有考虑过斜率DP,太菜了不会)

既然女生是去匹配男生的 , 那很容易啊 , 直接对男生建里凸包 , 然后让女生在男生的凸包里面去找到答案 , 因为我们知道凸包其实是一种最优的状态 ;但是!!!这其实是错误的 , 如果女的点没有在凸包里面这样思考就是正确的 , 但是女生是有可能在凸包里面的,所以不能建立凸包后在去配对 , 而是应该一边建立凸包一边找答案 , 为什么?  这是因为凸包有局部的最优状态 , 如果我们把所有的点对x排序 , 如果扫描到是男生就建立凸包 , 是女生就在凸包找答案 , 因为对女生来说如果想要在左边的男生里面找到最优的,肯定是在凸包里面找答案,为了加快我们可以二分找答案好吧  。 那问题来了 , 我们只是解决了女生在左边找男生 , 但是女的最优男生也有可能是在右边啊?  这时候我们就像找左边一样 , 从右到左建凸包 ,然后找答案

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define PI 3.1415926535
using namespace std;
#define ll long long
const int maxn=1e5+1;
struct node
{
    ll x,y;
    int id;
    int now;
};
node vex[maxn<<1];//存入的所有的点
node stackk[maxn],a[maxn],b[maxn];//凸包中所有的点
int ans[maxn];
bool cmp1(node a,node b)//排序找第一个点
{
    if(a.x==b.x)
        return a.y<b.y;
    else
        return a.x<b.x;
}

ll cross(node a,node b,node c)//计算叉积
{//向量ab在向量ac
//>0 顺时针方向
//<0 逆时针方向
//=0 平行
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
 
bool judge(node a , node b , node c)
{
    ll t=cross(a,b,c);
    return t==0?c.now<b.now : t<0;///相同的价值取编号最小
}
 
void solve(int t)
{
    int top=0;
    for(int i=1 ; i<=t ; i++)
    {
       if(vex[i].id==1)///男生就建立凸包
       {
           while( top >1&&  cross(stackk[top-1] , stackk[top] , vex[i])<0)
            top--;
           stackk[++top]=vex[i];
 
          // printf("%d\n",top);
       }
       else///*女生就在已有的男生凸包里面找答案
       {
           if(!top) continue;
           int head=1 , tail=top;
           while(head<tail)
           {
               int mid = (head + tail) >>1;
             //  ll T=cross(stackk[mid],stackk[mid+1],vex[i]);
              // cout<<T<<endl;
               if(cross(stackk[mid],stackk[mid+1],vex[i]) <= 0)  ///可以理解为从mid 断开 的凸包与女生是否可以了建立背包
                tail=mid;
               else
                head=mid+1;
 
           }
 
 
           if(ans[vex[i].now]==-1 || judge(b[vex[i].now] , a[ans[vex[i].now]] , a[stackk[head].now]))
           {
              ans[vex[i].now] = stackk[head].now;
 
           }
       }
    }
}
int main()
{
        int n,m;
        int t;
        scanf("%d%d",&n,&m);
        t=n+m;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld%lld",&vex[i].x,&vex[i].y);
            vex[i].id=1;
            vex[i].now=i;
            a[i]=vex[i];///记录男的
 
        }
        for(int i=1 ; i<=m ; i++)
        {
            scanf("%lld%lld",&vex[i+n].x,&vex[i+n].y);
            vex[i+n].id=2;
            vex[i+n].now=i;
            b[i]=vex[i+n];///记录女的
        }
 
            memset(stackk,0,sizeof(stackk));
            sort(vex+1,vex+t+1,cmp1);///对x排序跑一遍凸包
            memset(ans,-1,sizeof(ans));
            solve(t);
            reverse(vex+1 , vex+1+t);///从右往左求ub
            for(int i=1 ; i<=t ; i++)
            {
                vex[i].x=-vex[i].x;
                vex[i].y=-vex[i].y;
            }
            solve(t);
           for(int i=1 ; i<=m ; i++)
                printf("%d\n",ans[i]);
}
View Code

 

2019年华南理工大学程序设计竞赛(春季赛) 单身狗救星 (凸包+二分)

原文:https://www.cnblogs.com/shuaihui520/p/10718415.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!