POJ 2398(计算几何 叉积)

落日映苍穹つ 2022-05-18 02:39 297阅读 0赞

题目链接

题目大意:给你一个被n块挡板分隔成n+1个区域的盒子,给你m个点,从小到大输出含有点的个数的区域有多少个

分析:这题其实和POJ 2318差不多的只是输出不一样,还有每个隔板的读入顺序不一定是从左到右的,所以读入完以后用sort排个序,

这道题其实就是考对叉积的应用,计算矢量叉积是与直线和线段相关的算法的核心部分。

设矢量P = ( x1, y1 ),Q = ( x2, y2 ),则P × Q = x1*y2 - x2*y1,其结果是一个标量,对于叉积公式的推导,推荐参考这篇博客。

显然有性质 P × Q = - ( Q × P ) 和 P × ( - Q ) = - ( P × Q )。

叉积的一个非常重要性质是可以通过叉积的符号判断两个矢量相互之间的顺逆时针关系:

若 P × Q > 0 , 则P在Q的顺时针方向。即P在Q的右侧,Q在P的左侧。
若 P × Q < 0 , 则P在Q的逆时针方向。即P在Q的左侧,Q在P的右侧。
若 P × Q = 0 , 则P与Q共线,但可能同向也可能反向。

有了叉积,那我们就可以根据叉积来判断每个点和挡板的位置关系,也就是每个点和直线的位置关系,我们用二分来判断,逐渐缩小范围来确定每个点所在的区域,用一个答案数组来存储每个点所在的区域,再用一个数组来存储各个数量的点的区域的个数,最后输出即可。

  1. #include<map>
  2. #include<set>
  3. #include<cmath>
  4. #include<queue>
  5. #include<stack>
  6. #include<cstdio>
  7. #include<vector>
  8. #include<utility>
  9. #include<cctype>
  10. #include<cstring>
  11. #include<cstdlib>
  12. #include<iostream>
  13. #include<algorithm>
  14. #define inf 0x3f3f3f3f
  15. #define Clear(x) memset(x,0,sizeof(x))
  16. #define fup(i,a,b) for(int i=a;i<b;i++)
  17. #define rfup(i,a,b) for(int i=a;i<=b;i++)
  18. #define fdn(i,a,b) for(int i=a;i>b;i--)
  19. #define rfdn(i,a,b) for(int i=a;i>=b;i--)
  20. typedef long long ll;
  21. using namespace std;
  22. const double pi=acos(-1.0);
  23. const int maxn = 1e3+7;
  24. int ans[maxn],num[maxn];
  25. struct Point{
  26. int x,y;
  27. Point(){}
  28. Point(int _x,int _y){x=_x;y=_y;}
  29. };
  30. struct Line{
  31. Point a,b;
  32. Line(){}
  33. Line(Point _a,Point _b){a=_a;b=_b;}
  34. }line[maxn];
  35. bool cmp(Line u,Line v)
  36. {
  37. return u.a.x<v.a.x;
  38. }
  39. /**叉积--向量ca和向量cb求叉积*/
  40. int cross(Point a,Point b,Point c)
  41. {
  42. a.x-=c.x;a.y-=c.y;
  43. b.x-=c.x;b.y-=c.y;
  44. return a.x*b.y-a.y*b.x;
  45. }
  46. int main()
  47. {
  48. int n,m,x1,y1,x2,y2;
  49. while(~scanf("%d",&n)&&n)
  50. {
  51. Clear(ans);
  52. Clear(num);
  53. scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
  54. for(int i=0;i<n;i++)
  55. {
  56. int Ui,Li;
  57. scanf("%d%d",&Ui,&Li);
  58. line[i]=Line(Point(Ui,y1),Point(Li,y2));
  59. }
  60. line[n] = Line(Point(x2,y1),Point(x2,y2));
  61. sort(line,line+n+1,cmp);
  62. Point s;
  63. while(m--)
  64. {
  65. scanf("%d%d",&s.x,&s.y);
  66. int l=0,r=n;
  67. while(l<=r)
  68. {
  69. int mid=(l+r)>>1;
  70. if(cross(line[mid].b,line[mid].a,s)>0)
  71. r=mid-1;
  72. else l=mid+1;
  73. }
  74. ans[l]++;
  75. }
  76. for(int i=0;i<=n;i++)
  77. if(ans[i]) num[ans[i]]++;
  78. printf("Box\n");
  79. for(int i=1;i<=n;i++)
  80. if(num[i]) printf("%d: %d\n",i,num[i]);
  81. }
  82. return 0;
  83. }

发表评论

表情:
评论列表 (有 0 条评论,297人围观)

还没有评论,来说两句吧...

相关阅读

    相关 POJ 2318 (计算几何 )

    [题目链接][Link 1] 题意:给你一个被n块挡板分隔成n+1个区域的盒子,给你m个点,问你每个区域有多少个点。 分析:这道题其实就是考对叉积的应用,计算矢量叉积是与直