POJ 2318 (计算几何 叉积)

小灰灰 2022-05-18 02:37 281阅读 0赞

题目链接

题意:给你一个被n块挡板分隔成n+1个区域的盒子,给你m个点,问你每个区域有多少个点。

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

设矢量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 = 5e3+7;
  24. int ans[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. /**叉积--向量ca和向量cb求叉积*/
  36. int cross(Point a,Point b,Point c)
  37. {
  38. a.x-=c.x;a.y-=c.y;
  39. b.x-=c.x;b.y-=c.y;
  40. return a.x*b.y-a.y*b.x;
  41. }
  42. int main()
  43. {
  44. int n,m,x1,y1,x2,y2,first=1;
  45. while(~scanf("%d",&n)&&n)
  46. {
  47. if(first) first=0;
  48. else printf("\n");
  49. Clear(ans);
  50. scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
  51. for(int i=0;i<n;i++)
  52. {
  53. int Ui,Li;
  54. scanf("%d%d",&Ui,&Li);
  55. line[i] = Line(Point(Ui,y1),Point(Li,y2));
  56. }
  57. Point s;
  58. while(m--)
  59. {
  60. scanf("%d%d",&s.x,&s.y);
  61. int l=0,r=n-1;
  62. while(l<=r)
  63. {
  64. int mid = (l+r)>>1;
  65. if(cross(line[mid].b,line[mid].a,s)>0)
  66. {
  67. r=mid-1;
  68. }
  69. else l=mid+1;
  70. }
  71. ans[l]++;
  72. }
  73. for(int i=0;i<=n;i++)
  74. printf("%d: %d\n",i,ans[i]);
  75. }
  76. return 0;
  77. }

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

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

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

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

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

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

叉积的一个非常重要

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

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

性质是可以通过它的符号判断两矢量相互之间的顺逆时针关系:
  若 Q = 0 , 则P与Q共线,但可能同向也可能反向。

发表评论

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

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

相关阅读

    相关 Poj 2318 TOYS (+二分)

    好久没做计算几何了,随便找道题恢复下手感,明显感觉写复杂了。。。。 应该是最后一道用vc6.0敲的题了,下一道改用codeblocks 题意:给定一个长方形箱子,中间有n条

    相关 POJ 2318 (计算几何 )

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