POJ2318 TOYS(直接计算法)

来源:互联网 发布:linux shell编程输入 编辑:程序博客网 时间:2024/05/22 15:49

题目链接:http://poj.org/problem?id=2318


此题还可以用向量叉乘+二分查找的方法:http://blog.csdn.net/xuh723/article/details/22221229

(直接计算法很繁琐且不易理解,基本毫无价值(划去))


TOYS
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 9751 Accepted: 4653

Description

Calculate the number of toys that land in each bin of a partitioned toy box. 
Mom and dad have a problem - their child John never puts his toys away when he is finished playing with them. They gave John a rectangular box to put his toys in, but John is rebellious and obeys his parents by simply throwing his toys into the box. All the toys get mixed up, and it is impossible for John to find his favorite toys. 

John's parents came up with the following idea. They put cardboard partitions into the box. Even if John keeps throwing his toys into the box, at least toys that get thrown into different bins stay separated. The following diagram shows a top view of an example toy box. 
 
For this problem, you are asked to determine how many toys fall into each partition as John throws them into the toy box.

Input

The input file contains one or more problems. The first line of a problem consists of six integers, n m x1 y1 x2 y2. The number of cardboard partitions is n (0 < n <= 5000) and the number of toys is m (0 < m <= 5000). The coordinates of the upper-left corner and the lower-right corner of the box are (x1,y1) and (x2,y2), respectively. The following n lines contain two integers per line, Ui Li, indicating that the ends of the i-th cardboard partition is at the coordinates (Ui,y1) and (Li,y2). You may assume that the cardboard partitions do not intersect each other and that they are specified in sorted order from left to right. The next m lines contain two integers per line, Xj Yj specifying where the j-th toy has landed in the box. The order of the toy locations is random. You may assume that no toy will land exactly on a cardboard partition or outside the boundary of the box. The input is terminated by a line consisting of a single 0.

Output

The output for each problem will be one line for each separate bin in the toy box. For each bin, print its bin number, followed by a colon and one space, followed by the number of toys thrown into that bin. Bins are numbered from 0 (the leftmost bin) to n (the rightmost bin). Separate the output of different problems by a single blank line.

Sample Input

5 6 0 10 60 03 14 36 810 1015 301 52 12 85 540 107 94 10 0 10 100 020 2040 4060 6080 80 5 1015 1025 1035 1045 1055 1065 1075 1085 1095 100

Sample Output

0: 21: 12: 13: 14: 05: 10: 21: 22: 23: 24: 2

Hint

As the example illustrates, toys that fall on the boundary of the box are "in" the box.


题意:一个矩形区域(左上角为x1,y1,右上角为x2,y2),用n条线分割(保证输入顺序从左到右),每条线都从矩形上边至下边,且两两互不相交,因而将矩形划分成了n+1个区域。向区域中放置m个点,最后输出每个区域中各有多少点。(保证没有点正好在分割线上及在矩形区域外)


这题当时没有想到叉乘(计算几何题目做得不多。。),就用了原始的办法进行模拟。

用数组u,l表示直线的端点x坐标,数组k表示直线的斜率,ans表示每个区域的玩具个数。


利用lower_bound查找点对应的直线(lower_bound(u,u+n,ux)-u返回u数组中大于等于ux的第一个数的下标)

如果k1=k2,表示这个点横坐标完全在一条直线的左边,那么可以确定这个点在这条直线左边的区域中

否则则从k1条直线到k2条直线进行检查,分3种情况:

1.纵坐标在直线k1上方,且直线k1斜率为正数-->点在直线k1左边区域

2.纵坐标在直线k1下方,且直线k1斜率为负数-->点在直线k1左边区域

3.纵坐标相对于直线j的位置与相对于直线j+1的位置相同且直线j的斜率与直线j+1的斜率不同-->点在直线j+1左边区域


4.纵坐标相对于直线j的位置与相对于直线j+1的位置不同且直线j的斜率与直线j+1的斜率相同-->点在直线j+1左边区域


5.循环结束后没有出现以上情况-->点在直线k2左边区域

(不能理解的可以画图尝试)


判断点与直线关系则用点坐标与直线方程进行比较得到。

最后输出编号和ans数组即可。


#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>using namespace std;#define eps 1e-8int u[5005],l[5005],n,m,x0,y0,x2,y2,ans[5005];double k[5005];int dcmp(double x)//浮点数比较函数,返回1表示大于0,-1表示小于,0表示等于0{    return (x>eps)-(x<-eps);}int pd(int i,int ux,int uy)//进行ux,uy与直线i的比较,返回1表示在直线上方,-1表示在直线下方{    double yy=k[i]*(ux-u[i])+y0;    double yu=(double)uy;    return dcmp(yu-yy);}int main(){    while (scanf("%d",&n)!=EOF&&n!=0)    {          scanf("%d%d%d%d%d",&m,&x0,&y0,&x2,&y2);          memset(ans,0,sizeof(ans));          for (int i=0;i<n;i++)          {              scanf("%d%d",&u[i],&l[i]);              if (u[i]!=l[i]) k[i]=(double)(y0-y2)/(u[i]-l[i]);else k[i]=0;//注意如果直线垂直,那么不会有点和它比较(必然k1==k2或直接跳过),因此斜率无所谓          }          for (int i=0;i<m;i++)          {              int ux,uy;              scanf("%d%d",&ux,&uy);              int k1=lower_bound(u,u+n,ux)-u,k2=lower_bound(l,l+n,ux)-l;//找到比ux大的u,l数组下标              if (k1==k2) {ans[k1]++;continue;}//同一条直线则直接对应区域+1              if (k1>k2) {int t=k1;k1=k2;k2=t;}//保证k1<k2              int p=pd(k1,ux,uy);              if (p==dcmp(k[k1])) {++ans[k1];continue;}//判断情况1,2              bool flag=0;              for (int j=k1+1;j<k2;j++)              {                   int pp=pd(j,ux,uy);                   if (pp==p&&dcmp(k[j])!=dcmp(k[j-1])) {flag=1;++ans[j];break;}//情况3                   else if (pp!=p&&dcmp(k[j])==dcmp(k[j-1])) {flag=1;++ans[j];break;}//情况4                   p=pp;              }              if (flag==0) {++ans[k2];}//情况5          }          for (int i=0;i<=n;i++)          {              printf("%d: %d\n",i,ans[i]);          }          printf("\n");    }    return 0;}


0 0