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 ",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 ",ans[i]); }