POJ2398 计算几何外积+二分

本文介绍了一种算法,用于计算在给定线段形成的多个区域内,每个区域包含特定数量玩具的方法。通过二分查找和线段排序,实现了高效计算。

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

题意:给n个线段m个玩具和x1,y1,x2,y2 每条线段起点纵坐标y1 ,终点纵坐标y2  

玩具箱的边界由n条线段+(x1,y1)-(x1,y2),(x2,y1)-(x2,y2)共n+2条线段形成 n+1个区域

保证n个线段都在x1,y1,x2,y2内,不会有玩具在边上或超出边界

输出有多少个区域的玩具数目有K个 K>0 的任意数


思路:假设玩具是点P 红色是区域的号码,蓝色是线段的号码

要判断P在哪个区域里,先编好号码,不然二分会乱


对每个玩具进行l=0,r=n 共n+1个区域 二分找使得外积<0的号码最小的线段即可


对了,这题N条线段得先排序再二分


#include
#include
#include
#include
#include
#include
#include
#include
#define MOD  1e9+7
#define MaxN 100000
#define ll long long
#define INF  0x3f3f3f3f//1e9大一点 
#define scann(d) scanf("%d",&d)
#define scanl(d) scanf("%I64d",&d)
using namespace  std;
const double eps = 1e-8;
const double PI = acos(-1.0);
const double e  = 2.718281828459;

inline  int sgn(double a);
inline  ll gcd(ll a,ll b);
inline  ll mod_pow(ll x,ll n,ll mod); 			//快速幂 余数
inline  int b_s1(int *a,int l,int r,int k); 		//二分查找 [l,r)找k 找到返回下标

class point
{
	public:
		int x,y;
		point()
		{
		}
		point(int a,int b)
		{
			x=a,y=b;
		}
		point operator -(const point &b)const
		{
			return point(x - b.x,y - b.y);

		}
		//叉积
		int operator ^(const point &b)const
		{
			return x*b.y - y*b.x;
		}
		//点积
		int operator *(const point &b)const
		{
			return x*b.x + y*b.y;     //绕原点旋转角度B(弧度值),后x,y的变化
		}
} points[1005];
struct line
{
	point s,e;
	line() {}
	line(point _s,point _e)
	{
		s = _s;
		e = _e;
	}
} lines[1005];

ll xmult(point p0,point p1,point p2) //计算p0p1 X p0p2  
{
	return (p1-p0)^(p2-p0);
}
bool C(int mid)
{
//	if()return true;

	return false;
}
bool cmp(line a,line b)
{
	if(a.s.x!=b.s.x)return a.s.x<b.s.x;
	else
		return a.e.x>n)
	{
		if(n==0)
			break;
		int m,x1,y1,x2,y2;
		cin>>m>>x1>>y1>>x2>>y2;
		for(int i=0; i>t1>>t2;
			lines[i].s=point(t1,y1);
			lines[i].e=point(t2,y2);
		}
		sort(lines,lines+n,cmp);
		lines[n].s=point(x2,y1);
		lines[n].e=point(x2,y2);
		lines[n+1].s=point(x1,y1);
		lines[n+1].e=point(x1,y2);
		mapm1;
		m1.clear();
		while(m--)
		{
			int pt1,pt2;
			cin>>pt1>>pt2;
			point t=point(pt1,pt2);
			//二分死大头 
			int l=0;//左
			int r=n;//右
			int mid=0;//中间
			int count=0;//二分次数;
			int ans=0;//答案的下标
			while(l<=r)
			{
				count++;
				mid=(l+r)/2;
				//	cout<<count<<" l:"<<l<<" r:"<<r<<" mid:"<<mid<<endl;
				if(xmult(t,lines[mid].s,lines[mid].e)<0)//bool C(mid);
				{
					ans=mid;//二分找满足if条件的最小mid
					r=mid-1;
				}
				else
				{
					//ans1=mid;//二分找满足else条件的最大mid
					l=mid+1;
				}
			}
			m1[ans]++;
		}
		cout<<"Box"<<endl;
		mapm2;
		for(map::iterator poi=m1.begin(); poi!=m1.end(); poi++)
		{
			m2[poi->second]++;
		}
		for(map::iterator poi=m2.begin(); poi!=m2.end(); poi++)
		{
			cout<first<<": "<second<<endl;
		}
	}
	return 0;
}


















inline int sgn(double a)
{
	return a < -eps ? -1 : a < eps ? 0 : 1;
}

inline ll gcd(ll a,ll b)
{
	return a==0?b:gcd(b%a,a);
}

ll mod_pow(ll x,ll n,ll mod)//快速幂 余数
{
	ll res=1;
	while(n>0)
	{
		if(n&1)//n的二进制最右位是1,即奇数
			res=res*x%mod;
		x=x*x%mod;
		n=n>>1;		 //相当于n/=2;
	}
	return res;
}
int b_s1(int *a,int l,int r,int k)//   二分查找 [l,r)找k 找到返回下标 log(n);
{
	int m;
	while(l<r)
	{
		m=l+(r-l)/2;
		if(a[m]==k)
			return m;
		else if(a[m]<k)
			l=m+1;
		else
			r=m;
	}
	return -1;
}ssssss



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值