题目地址:http://poj.org/problem?id=2318
题目:
给出长方形的左上角(x1,y1)右下角(x2,y2),n块木板把这个长方形分割成n+1个区域(给出木板的左上和右下坐标),m个玩具,给出这个m个玩具的具体坐标,忽略玩具的体积,问0-n这个n+1个区域,每个区域内的玩具数。
注意:玩具不会落在两个区域的公共边上,区域不相交
解题思路:
不要用点在多边形内判定的模版,很可能会超时,这个多边形是个凸多边形,直接判定这个点是否都在边的左侧即可,注意边的方向是顺时针的!!玩具不会落在木板上!且不会超出长方形区域!
(1)直接暴力跑了1.8ms,在超时的边缘试探
(2)二分:从左到右找到第一个在toy坐标右边的木板,这个toy就位于该木板左侧的区域内,时间快很多
ac代码:
暴力:
#include<iostream>
#include <vector>
#include<math.h>
using namespace std;
const int maxn = 5005;
const double pi = acos(-1.0);
const double eps = 1e-10;
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator - (Vector a, Vector b)//向量减法
{
return Vector(a.x - b.x, a.y - b.y);
}
int dcmp(double x)//精度三态函数(>0,<0,=0)
{
if (fabs(x) < eps)return 0; //等于
else return x < 0 ? -1 : 1;//小于,大于
}
double Cross(Vector a, Vector b)//外积
{
return a.x * b.y - a.y * b.x;
}
struct node{
int cnt;
vector<Point> ps;
node(int cnt = 0):cnt(cnt) {ps.clear(); }
}ans[maxn];
int n, m, x_1, y_1, x_2, y_2, ui, li;
Point toy[maxn];
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
int line = 0;
while(scanf("%d", &n))
{
if(!n) break;
if(line) printf("\n");
line = 1;
scanf("%d %d %d %d %d", &m, &x_1, &y_1, &x_2, &y_2);
for(int i = 0; i < maxn; i++) ans[i].ps.clear(), ans[i].cnt = 0;
//左上a, 右下b
ans[0].ps.push_back(Point(x_1, y_1));
ans[0].ps.push_back(Point(x_1, y_2));
for(int i = 0; i < n; i++)
{
//(Ui,y1) and (Li,y2)
scanf("%d %d", &ui, &li);
//b,a
ans[i].ps.push_back(Point(li, y_2));
ans[i].ps.push_back(Point(ui, y_1));
//下一个区间a,b
ans[i+1].ps.push_back(Point(ui, y_1));
ans[i+1].ps.push_back(Point(li, y_2));
}
//b,a
ans[n].ps.push_back(Point(x_2, y_2));
ans[n].ps.push_back(Point(x_2, y_1));
for(int k = 0; k < m; k++)
{
scanf("%lf %lf", &toy[k].x, &toy[k].y);
for(int i = 0; i <= n; i++)
{
int in = 1;
for(int j = 0; j < 4; j++) // 多边形是凸多边形,不需复杂判断,反而可能会超时,包括toy在上下边界的情况
{
int cross = dcmp(Cross(ans[i].ps[(j+1)%4] - ans[i].ps[j], toy[k] - ans[i].ps[j]));
if(cross < 0) in = 0;
}
if(in)
{
ans[i].cnt++;
break;
}
}
}
for(int i = 0; i <= n; i++)
{
printf("%d: %d\n", i, ans[i].cnt);
}
}
return 0;
}
二分:(参考博客:https://blog.csdn.net/qq_36782366/article/details/77899164)
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const double eps=1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
return x<0?-1:1;
}
const int maxn=5000+10;
struct Point
{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
};
typedef Point Vector;
Vector operator-(Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y);
}
double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
Point p[maxn];//需要判断位置的所有点
Point up[maxn],down[maxn];//记录上一排的n+1个点,和下一排的n+1个点
Point poly[maxn][4];
int ans[maxn];//保存第i个隔间有几个点
int main()
{
int n,m;
double x1,y1,x2,y2;
bool first=true;
while(scanf("%d",&n)==1 && n)
{
if(!first) printf("\n");
first=false;
scanf("%d%lf%lf%lf%lf",&m,&x1,&y1,&x2,&y2);
up[0]=Point(x1,y1);
up[n+1]=Point(x2,y1);
down[0]=Point(x1,y2);
down[n+1]=Point(x2,y2);
for(int i=1;i<=n;++i)
{
scanf("%lf%lf",&x1,&x2);
up[i]=Point(x1,y1);
down[i]=Point(x2,y2);
}
memset(ans,0,sizeof(ans));
for(int i=1;i<=m;++i)
{
double x,y;
scanf("%lf%lf",&p[i].x,&p[i].y);
int l = 1,r = 1+n;
int tmp;
while( l <= r)
{
int mid = (l + r)/2;
if(dcmp (Cross(up[mid]-down[mid], p[i]-down[mid]) )>0)
{
tmp = mid;
r = mid - 1;
}
else l = mid + 1;
}
ans[tmp-1]++;
}
for(int i=0;i<=n;++i)
printf("%d: %d\n",i,ans[i]);
}
return 0;
}