首先声明叉积在计算几何是基本用法!!他的奶名就叫做向量积!!(好熟悉的称呼)
那么叉积主要注意方向问题:他是以前面的向量为起点转向另外那个向量的角度!!
Wall HDU 1348
一道模板题!!(凸包问题)
三步骤:排序,再排序,再是重点进行判断!!!
先进行排序,从小到大找出最左下角的一个坐标!
之后以这个坐标找出每个点的极角(用个三角公式atan2(y,x))
之后以三点为核心进行判断!!!
如果第三点在前两点连线的左边可以,不然回溯再进行判断!!
具体参见:http://hi.baidu.com/nicker2010/item/757c4350688a86a3adc857ed
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<math.h> 5 #define PI 3.14159265 6 using namespace std; 7 struct line 8 { 9 double x; 10 double y; 11 double angle; 12 }a[1010],b[1010]; 13 double comp(line i,line j) 14 { 15 if(i.y==j.y) 16 return i.x<j.x; 17 return i.y<j.y; 18 } 19 double comp1(line i,line j) 20 { 21 if(i.angle==j.angle) 22 { 23 if(i.x==j.x) 24 return i.y>j.y; 25 return i.x>j.x; 26 } 27 return i.angle<j.angle; 28 } 29 double add(line i,line j,line z) 30 { 31 double a1=z.y-i.y; 32 double a2=z.x-i.x; 33 double a3=z.y-j.y; 34 double a4=z.x-j.x; 35 return a2*a3-a1*a4; 36 } 37 double abb(line i,line j) 38 { 39 return sqrt((i.y-j.y)*(i.y-j.y)+(i.x-j.x)*(i.x-j.x)); 40 } 41 int main() 42 { 43 int t,n,i,j,top; 44 double m,len; 45 scanf("%d",&t); 46 while(t--) 47 { 48 scanf("%d%lf",&n,&m); 49 for(i=1;i<=n;i++) 50 scanf("%lf%lf",&a[i].x,&a[i].y); 51 sort(a+1,a+n+1,comp);//排序 52 for(i=2;i<=n;i++) 53 a[i].angle=atan2(a[i].y-a[1].y,a[i].x-a[1].x);//求极角 54 sort(a+2,a+1+n,comp1);//再排序,第一个坐标不用排序 55 b[1]=a[1];//*********** 56 b[2]=a[2]; 57 b[3]=a[3]; 58 top=4; 59 for(i=4;i<=n;i++) 60 { 61 while(top>3&&add(b[top-2],b[top-1],a[i])<=0)//以三点进行判断 62 top--; 63 b[top++]=a[i]; 64 }//**************核心 65 len=abb(b[1],b[top-1]); 66 for(i=2;i<top;i++) 67 len+=abb(b[i],b[i-1]); 68 len+=2*PI*m; 69 printf("%.0lf ",len); 70 if(t) 71 printf(" "); 72 } 73 return 0; 74 }
Circuit Board ZOJ 1648
怎么用叉积判断两线段是否相交!!
有一种方法叫做:跨立实验
如果两线段相交,则两线段必然相互跨立对方。
若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,
即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。
那么就好做了:
1 #include<iostream> 2 #include<algorithm> 3 #include<stdio.h> 4 #include<math.h> 5 using namespace std; 6 struct line 7 { 8 double x; 9 double y; 10 }a[2005],b[2005]; 11 double abb(double x1,double y1,double x2,double y2) 12 { 13 return x1*y2-y1*x2; 14 } 15 bool add(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4) 16 { 17 double temp1,temp2,temp3,temp4; 18 temp1=abb(x1-x3,y1-y3,x4-x3,y4-y3); 19 temp2=abb(x4-x3,y4-y3,x2-x3,y2-y3); 20 if(temp1*temp2>0) 21 return true; 22 return false; 23 } 24 int main() 25 { 26 int i,j,n,d; 27 while(scanf("%d",&n)!=EOF) 28 { 29 for(i=1;i<=n;i++) 30 scanf("%lf%lf%lf%lf",&a[i].x,&a[i].y,&b[i].x,&b[i].y); 31 d=0; 32 for(i=1;i<=n-1;i++) 33 { 34 for(j=i+1;j<=n;j++) 35 { 36 if(add(a[i].x,a[i].y,b[i].x,b[i].y,a[j].x,a[j].y,b[j].x,b[j].y)) 37 { 38 d=1; 39 break; 40 } 41 } 42 if(d==1) 43 break; 44 } 45 if(d==1) 46 printf("burned! "); 47 else 48 printf("ok! "); 49 } 50 return 0; 51 }//坐标表示可用结构体
Toy Storage POJ 2398
考点是:一个点是否在一个多边形内外!
但是这个题目的构造直接判断点在两条线段里面还是外面就可以了。。。
其实你都可以
把这个点做平行于x轴的射线,直接解方程得出x判断大小就可以了。。。
基本就是用叉积判断正负(也就是叉积的方向)。。。
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 int b[10005],n,y2,y1,x1,x2,x12,y12,m,i,c,x; 7 struct line 8 { 9 int x1; 10 int x2; 11 }a[1005]; 12 int comp1(line i,line j) 13 { 14 return i.x1<j.x1; 15 } 16 double abb(double x,double y,double x1,double y1) 17 { 18 return x*y1-x1*y; 19 } 20 int add(double x,int y,int i) 21 { 22 double d,d1; 23 d=abb(a[i].x1-x,y1-y,a[i].x2-x,y2-y); 24 if(i==1) 25 { 26 if(d<0) 27 { 28 b[i]++; 29 return 1; 30 } 31 } 32 else if(i==n+1) 33 { 34 if(d>0) 35 { 36 b[i]++; 37 return 1; 38 } 39 } 40 else 41 { 42 d1=abb(a[i-1].x1-x,y1-y,a[i-1].x2-x,y2-y); 43 if(d<0&&d1>0) 44 { 45 b[i]++; 46 return 1; 47 } 48 } 49 return 0; 50 } 51 int main() 52 { 53 while(scanf("%d",&n)!=EOF) 54 { 55 if(n==0) 56 break; 57 memset(b,0,sizeof(b)); 58 scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2); 59 for(i=1;i<=n;i++) 60 scanf("%d%d",&a[i].x1,&a[i].x2); 61 sort(a+1,a+1+n,comp1); 62 a[n+1].x1=a[n].x1;a[n+1].x2=a[n].x2; 63 while(m--) 64 { 65 scanf("%d%d",&x12,&y12); 66 for(i=1;i<=n+1;i++) 67 if(add(x12,y12,i)) 68 break; 69 } 70 sort(b+1,b+1+n+1); 71 int d=0; 72 c=1;x=0; 73 printf("Box "); 74 for(i=1;i<=n+1;i++)//*******输出形式搞了很久 75 { 76 if(b[i]!=0) 77 { 78 c=b[i]; 79 while(b[i]==c&&i<=n+1) 80 { 81 if(d==0) 82 printf("%d: ",b[i]); 83 d=1; 84 i++; 85 x++; 86 } 87 printf("%d ",x); 88 x=0; 89 d=0; 90 i--; 91 } 92 }//************** 93 } 94 return 0; 95 }
Area ZOJ 1010
一道简单的题目。。。
主要判断是不是多边形!!!
具体参见:http://blog.sina.com.cn/s/blog_5ced353d0100b1xd.html
1 #include<iostream> 2 #include<algorithm> 3 #include<stdio.h> 4 using namespace std; 5 double a[1005],b[1005]; 6 double abb(int i,int j,int k) 7 { 8 return (a[j]-a[i])*(b[j]-b[k])-(a[j]-a[k])*(b[j]-b[i]); 9 } 10 int add(int x1,int y1,int x2,int y2) 11 { 12 if(abb(x2,x1,y1)*abb(y2,x1,y1)>0)//两次判断 13 return 0; 14 if(abb(x1,x2,y2)*abb(y1,x2,y2)>0) 15 return 0; 16 return 1; 17 } 18 int main() 19 { 20 int w=0,d,i,j,n; 21 double s; 22 while(scanf("%d",&n)!=EOF&&n) 23 { 24 if(w) 25 printf(" "); 26 for(i=0;i<n;i++) 27 scanf("%lf%lf",&a[i],&b[i]); 28 if(n<3) 29 { 30 printf("Figure %d: Impossible ",++w); 31 continue; 32 } 33 d=0; 34 for(i=1;i<=n-1;i++) 35 { 36 for(j=1;j<=i-2;j++) 37 if(add(i,i-1,j,j-1))//只需判断不相邻的边是否相交 38 {d=1;break;} 39 if(d==1) 40 break; 41 } 42 if(d==1) 43 {printf("Figure %d: Impossible ",++w);continue;} 44 for(i=2;i<n-1;i++) 45 if(add(0,n-1,i,i-1)) 46 {d=1;break;} 47 if(d==1) 48 {printf("Figure %d: Impossible ",++w);continue;} 49 s=0; 50 for(i=1;i<n;i++) 51 s+=a[i-1]*b[i]-a[i]*b[i-1]; 52 s+=a[n-1]*b[0]-a[0]*b[n-1]; 53 if(s<0) 54 s*=-1; 55 printf("Figure %d: %.2lf ",++w,s/2); 56 } 57 return 0; 58 }