Chiryen

导航

HDOJ(2056)&HDOJ(1086)

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;
}
View Code

 

 

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;
}
View Code

 

跨立实验可用叉积来解决:设这四个点为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两侧同理。

 

posted on 2014-01-04 17:21  Chiryen  阅读(468)  评论(0编辑  收藏  举报