POJ2280 Amphiphilic Carbon Molecules

本文介绍了一种计算几何问题的解决方案,通过枚举基准点并按极角排序向量,实现高效扫描并计算溶解点数。引入了巧妙的方法,即通过基准点对称位置变换减少计算复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

完全不会计算几何。。。不过这题虽然是查别人的题解的,但是还是值得写一下题解来进一步解释一下。

思路是枚举一个基准点,将基准点到所有其他的点的向量按照极角排序,然后依次将每一个向量作为一种放置方法(下面把这个取出来作为基准的向量叫做基准向量,ICPC放在与基准向量共线的直线上,从向量的方向看过去,向量所在直线的左侧溶解color为0的点)扫描这种放置方式下溶解的点的数目。这里有个非常巧妙的地方,将color为1的点放到关于基准点对称的位置上,那么我们扫描时只需要将扫描向量从基准向量开始旋转180°记录下所有扫描线经过的点即可。

同时,当基准向量旋转时,只需要从上次扫描向量停下来的地方开始扫描,同时减去基准向量转过的区域内包括的点即可(由于基准向量每次只移动一个点,所以每次移动基准向量时,点的数目要在原先的基础上减去1,当扫描向量与基准向量重合的时候(这种情况是存在的:当所有的点全都共线的时候以第一个点作为基准点,每次移动基准向量,扫描向量都是从与基准向量重合的位置开始扫描的。),可以视为是刚开始扫描,先加上一个点后在扫描完成后减去,以与之前的过程保持一致)

AC代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

struct point
{
	int x,y;
	double rad;
	point(int xx=0,int yy=0,double r=0.0):x(xx),y(yy),rad(r){}
	bool operator< (const point &a)const
	{
		return rad<a.rad;
	}
};

point p[10005],v[10005];
int color[10005];

bool left(point a,point b)
{
	return a.x*b.y-a.y*b.x>=0;
}

int main(int argc, char const *argv[])
{
	int n;
	while(scanf("%d", &n)&&n!=0)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%d %d %d", &p[i].x,&p[i].y, &color[i]);
		}  
		int ans=0;
		for(int i=0;i<n;i++)
		{
			int k=0;
			for(int j=0;j<n;j++)
			{
				if(j!=i)
				{
					v[k].x=p[j].x-p[i].x;
					v[k].y=p[j].y-p[i].y;
					if(color[j])
					{
						v[k].x=-v[k].x;
						v[k].y=-v[k].y;
					}
					v[k].rad=atan2((double)v[k].y,(double)v[k].x);
					k++;
				}
			}
			if(k<=2)
			{
				ans=n;
				break;
			}
			sort(v,v+k);
			int L=0,R=0,cnt=2;
			for(L=0;L<k;L++)
			{
				if(L==R)
				{	
					R=(R+1)%k;
					cnt++;
				}
				while(L!=R&&left(v[L],v[R]))
				{
					R=(R+1)%k;
					cnt++;
				}
				cnt--;
				ans=max(ans,cnt);
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值