Rectangles HDOJ(2056)
http://acm.hdu.edu.cn/showproblem.php?pid=2056
题目描述:给2条线段,分别构成2个矩形,求2个矩形相交面积。
算法:先用快速排斥判断2个矩形是否相交。若不相交,面积为0。若相交,将x坐标排序去中间2个值之差,y坐标也一样。最后将2个差相乘得到最后结果。
这题是我大一的时候做过的,当时一看觉得很水,写起来发现其实没我想的那么水。分了好几类情况没做出来。今天看了点关于判断线段相交的知识,想起了这题便拿来练手。快速排斥之后又准备分类讨论,越想分类情况越多。后来意外想到了取各自坐标方向的2个中值之差(如x1,x2,x3,x4,是按从小到大排列的,取x3-x2,同理y3-y2)。最后2个差相乘就是相交面积。泪牛满面!
#include <iostream> #include <iomanip> #include <cstdlib> using namespace std; int cmp(const void *a,const void *b) { return *(double*)a-*(double*)b; } double min(double a,double b) { return a<b?a:b; } double max(double a,double b) { return a>b?a:b; } bool intersected(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4) { if(min(x1,x2)<max(x3,x4)&& min(x3,x4)<max(x1,x2)&& min(y1,y2)<max(y3,y4)&& min(y3,y4)<max(y1,y2)) //快速排斥判断2矩形是否相交 return true; else return false; } double getmiddiff(double a[4]) //取次小和次大的2个数之差,没想到好的办法,于是用了快排 { qsort(a,4,sizeof(double),cmp); return a[2]-a[1]; } int main() { double x1,y1,x2,y2,x3,y3,x4,y4; double temp[4]; while(cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4) { if(intersected(x1,y1,x2,y2,x3,y3,x4,y4)) { temp[0]=x1; temp[1]=x2; temp[2]=x3; temp[3]=x4; double xdiff=getmiddiff(temp); temp[0]=y1; temp[1]=y2; temp[2]=y3; temp[3]=y4; double ydiff=getmiddiff(temp); cout<<fixed<<setprecision(2)<<xdiff*ydiff<<endl; //需要<iomanip> } else cout<<"0.00"<<endl; //一开始是cout<<"0"<<endl;WA了一次,SB } return 0; }
You can Solve a Geometry Problem too HDOJ(1086)
http://acm.hdu.edu.cn/showproblem.php?pid=1086
题目描述:给n条线段,求相交点的个数。
算法:老套路,遍历任意两条线段,用快速排斥判断2个矩形是否相交。这题用跨立实验,即以其中一条线段为直线,判断另一线段的两端点是否在它两边。使用2次跨立实验。
#include <iostream> #include <vector> #include <algorithm> using namespace std; struct line { double x1,y1; double x2,y2; }; bool Exclude(line l1,line l2) //快速排斥 { if(min(l1.x1,l1.x2)<=max(l2.x1,l2.x2) &&min(l2.x1,l2.x2)<=max(l1.x1,l1.x2) &&min(l1.y1,l1.y2)<=max(l2.y1,l2.y2) &&min(l2.y1,l2.y2)<=max(l1.y1,l1.y2)) //相等的时候说明2个矩形有公共点 return true; else return false; } bool Straddle(line l1,line l2) //跨立实验 { //3个向量 double t1=l1.x1-l1.x2; double w1=l1.y1-l1.y2; double t2=l1.x1-l2.x1; double w2=l1.y1-l2.y1; double t3=l1.x1-l2.x2; double w3=l1.y1-l2.y2; //求叉积 double cross1_2=(t1*w2-t2*w1); double cross1_3=(t1*w3-t3*w1); if(cross1_2*cross1_3<=0) return true; else return false; } bool isIntersect(line l1,line l2) { if(Exclude(l1,l2)&&Straddle(l1,l2)&&Straddle(l2,l1)) return true; else return false; } int main() { int n,res; vector<line> v; while(cin>>n&&n) { v.clear(); line temp; res=0; for(int i=0;i<n;i++) { cin>>temp.x1>>temp.y1>>temp.x2>>temp.y2; v.push_back(temp); } int len=v.size(); for(int i=0;i<len-1;i++) { for(int j=i+1;j<len;j++) { if(isIntersect(v[i],v[j])) res++; } } cout<<res<<endl; } return 0; }
跨立实验可用叉积来解决:设这四个点为x1,y1,x2,y2,x3,y3,x4,y4L1的坐标为t1=x1-x2,w1=y1-y2,1端点到3,4的线段向量分别为t2=x1-x3,w2=y1-y3,t3=x1-x4,w3=y1-y4;则3,4在L1两端即为(t1*w2-t2*w1)*(t1*w3-t3*w1)<=0 ,如果等于0则有一点在直线L1上,属于非规范相交判断L1的两点在L2两侧同理。