两亲性分子(极角排序)

/*假设隔板一定经过两个点,依次枚举两个点和两侧的数量,O(n^3),TLE*/
/*
#include <iostream>
#include <cstring> 

using namespace std;

const int N=1010;

struct point {
	int x,y,num;
}dot[N]; 

 int main()
 {
 	int n;
	 while(cin>>n && n)
	{
		memset(dot,0,sizeof dot); 
		for(int i=0;i<n;i++)
		{
			int x,y,num;
			cin>>x>>y>>num;
			dot[i]={x,y,num};
		} 
		
		int ans=0;
		for(int i=0;i<n;i++)
			for(int j=i+1;j<n;j++)
			{
				int x1=dot[i].x,y1=dot[i].y;
				int x2=dot[j].x,y2=dot[j].y;
				double k=((y2-y1)*(1.0))/(x2-x1);
				double b=y2-k*x2;
				
				int cnt_a1=0,cnt_a0=0,cnt_d0=0,cnt_d1=0;
				for(int s=0;s<n;s++)
				{
					int sx=dot[s].x;
					int sy=dot[s].y;
					
					if(sx*k+b <= sy) {
						if(dot[s].num==0) 
						{
							//if( x1==-1 && y1==0 && x2==1 && y2==2 ) cout<<"这条直线以上白点的坐标:",cout<<sx<<' '<<sy<<endl;
							cnt_a0++;
						}
						else cnt_a1++;
					}
					 if(sx*k+b >= sy)
					{
						if(dot[s].num==0) cnt_d0++;
						else cnt_d1++;
					}
					
				}
				if(cnt_a0+cnt_d1>ans) 
				{
					ans=cnt_a0+cnt_d1;
				}
				if(cnt_d0+cnt_a1>ans) 
				{
					ans=cnt_d0+cnt_a1;
				}
			}
			
		cout<<ans<<endl;	
	} 
	return 0;
 } 
 */
 //以一个点为基准点,利用此基准点对其他店进行坐标变换,计算极角,并进行排序,排序之后比较坐标进行计数
 //极角排序
 //统计一侧黑点一侧白点总数,可以将黑点进行坐标变换,从而实现只排序一侧 
 //基准点枚举O(n),在枚举基准点的基础上排序并计数 所以复杂度是O(n^2logn) 
#include <iostream>
#include <cstring> 
#include <cmath>
#include <algorithm>

using namespace std;

const int N=1010;

struct point {
	int x,y,num;
	double angle;
	bool operator < (const point&a)const 
	{
		return angle < a.angle;
	}
}dot[N],sdot[N]; 

bool isleft(point A,point B)
{
    return A.x*B.y-A.y*B.x>=0;
}

 int main()
 {
 	int n;
	 while(cin>>n && n)
	{
		memset(dot,0,sizeof dot); 
		for(int i=0;i<n;i++)
		{
			int x,y,num;
			cin>>x>>y>>num;
			dot[i]={x,y,num};
		}
		int ans=0;
		//基准点 
		for(int i=0;i<n;i++)
		{
			int k=0;
			memset(sdot,0,sizeof sdot);
			for(int j=0;j<n;j++)
			{
				if(i==j) continue;
				sdot[k].x=dot[j].x-dot[i].x;
				sdot[k].y=dot[j].y-dot[i].y;
				//如果是黑色,翻转,对面黑色翻转到本测,本测黑色翻转到对面,从而实现只统计一侧的效果 
				if(dot[j].num==1) sdot[k].x=-sdot[k].x, sdot[k].y=-sdot[k].y;
				sdot[k].angle=atan2(sdot[k].y,sdot[k].x);
				k++; 
			} 
			sort(sdot,sdot+k);
			
			//O-sdot[l]作为分割线,O-sdot[r]作为扫描线,扫描线扫过180° 
			int l=0,r=0;
			int cnt=2;
			while(l<k)
			{
				//这里非常不明白,为什么扫描线和分割线一致的时候,cnt要++,并且后面cnt要-- 
				if(l==r) r=(r+1)%k,cnt++;
				while(l!=r && isleft(sdot[l],sdot[r])) 
				{
					r=(r+1)%k;
					cnt++;
				}
				l++;
				cnt--;
				ans=max(ans,cnt);
			}
		}
		cout<<ans<<endl;	
	}
	return 0; 
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值