计算几何+简单图论

题目:http://poj.org/problem?id=1556

题意:

给出一个(0,0)(0,10)(10,0)(10,10)的正方形房子,里面有一些墙,每堵墙上有两扇门;

求从(0,5)到(10,5)的最短距离;

题解:

本题结合了计算几何和最短路,是一道综合性的题目。

首先建一个有向图,把(0,5)作为起始点,(10,5)作为目标点,其他所有墙上的门的两个端点也加入到这个有向图中;

尝试枚举连接任意两个点,只有当这两个点之间没有墙阻隔,这连个点才可能连接起来;

所有能连接起来的两个点都作为一条有向边加入到有向图中,并且靠左的作为u,靠右的作为v,而两点之间的距离作为w;

最后,我们只要求出起始点和目标点之间的最短路即可。

题目特点:

每一列的点是有顺序的,利用这个特点,可以确定哪些是墙,哪些是窗子。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<queue>
#define MAXN 4*20
#define INF 0x3f3f3f3f
using namespace std;

//--------------------------------------计算几何模板 - st--------------------------------------

const double eps = 1e-6;

struct Point{
    double x,y;
    Point(double tx=0,double ty=0):x(tx),y(ty){}
};
typedef Point Vctor;

//向量的加减乘除
Vctor operator + (Vctor A,Vctor B){return Vctor(A.x+B.x,A.y+B.y);}
Vctor operator - (Point A,Point B){return Vctor(A.x-B.x,A.y-B.y);}
Vctor operator * (Vctor A,double p){return Vctor(A.x*p,A.y*p);}
Vctor operator / (Vctor A,double p){return Vctor(A.x/p,A.y/p);}

int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    else return (x<0)?(-1):(1);
}
bool operator == (Point A,Point B){return dcmp(A.x-B.x)==0 && dcmp(A.y-B.y)==0;}

//向量的点积,长度,夹角
double Dot(Vctor A,Vctor B){return A.x*B.x+A.y*B.y;}
double Length(Vctor A){return sqrt(Dot(A,A));}
double Angle(Vctor A,Vctor B){return acos(Dot(A,B)/Length(A)/Length(B));}

//叉积,三角形面积
double Cross(Vctor A,Vctor B){return A.x*B.y-A.y*B.x;}
double TriangleArea(Point A,Point B,Point C){return Cross(B-A,C-A);}

//判断线段是否规范相交
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    double c1 = Cross(a2 - a1,b1 - a1), c2 = Cross(a2 - a1,b2 - a1),
           c3 = Cross(b2 - b1,a1 - b1), c4 = Cross(b2 - b1,a2 - b1);
    return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}

//--------------------------------------计算几何模板 - ed--------------------------------------

//--------------------------------------spfa算法 - st--------------------------------------
double d[MAXN];
double mp[MAXN][MAXN];
bool vis[MAXN];  
void init(int n){
	for(int i=0;i<n;i++) 
		for(int j=0;j<n;j++) 
			mp[i][j]=0;
}
			
void addedge(int u,int v,double w)
{
	mp[u][v]=w;
}

//spfa求最短路 
void spfa(int st,int n)
{
	//初始化,第一个点距离0,其他点距离正无穷 
    for(int i=0;i<n;i++)
    {
        i==st ? d[i]=0 : d[i]=INF;
        vis[i]=0;
    }
    
    queue<int> q;
    q.push(st);
    vis[st]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;
        for(int v=0;v<n;v++)
        {
            if(u==v || mp[u][v]==0) continue;
            double tmp=d[v];
            if(d[v]>d[u]+mp[u][v]) d[v]=d[u]+mp[u][v];
            if(d[v]<tmp && !vis[v])
            {
                q.push(v);
                vis[v]=1;
            }
        }
    }
}
//--------------------------------------spfa算法 - ed--------------------------------------

int n;
vector<Point> p;
int main()
{
    while(scanf("%d",&n) && n!=-1)
    {
        p.clear();
        p.push_back(Point(0,5));
        for(int i=1;i<=n;i++)
        {
            double x,y1,y2,y3,y4;
            scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
            p.push_back(Point(x,y1));
            p.push_back(Point(x,y2));
            p.push_back(Point(x,y3));
            p.push_back(Point(x,y4));
        }
        p.push_back(Point(10,5));

        int _size=p.size();
        init(_size);
        for(int i=0;i<_size;i++)
        {
            for(int j=i+1;j<_size;j++)
            {
                if(p[i].x==p[j].x) continue;

                bool ok=1;
                for(int k=i+1;k<j;k++)
                {
                    if(k%4==1)
                    {
                        if(SegmentProperIntersection(p[i],p[j],p[k],Point(p[k].x,0)))
                        {
                            ok=0;
                            break;
                        }
                    }
                    else if(k%4==2)
                    {
                        if(SegmentProperIntersection(p[i],p[j],p[k],p[k+1]))
                        {
                            ok=0;
                            break;
                        }
                    }
                    else if(k%4==3)
                    {
                        if(SegmentProperIntersection(p[i],p[j],p[k],p[k-1]))
                        {
                            ok=0;
                            break;
                        }
                    }
                    else if(k%4==0)
                    {
                        if(SegmentProperIntersection(p[i],p[j],p[k],Point(p[k].x,10)))
                        {
                            ok=0;
                            break;
                        }
                    }
                }
                if(ok) addedge(i,j,Length(p[i]-p[j]));
            }
        }

        spfa(0,_size);
        printf("%.2f\n",d[_size-1]);
    }
    
    return 0; 
}
发布了22 篇原创文章 · 获赞 7 · 访问量 407

猜你喜欢

转载自blog.csdn.net/qq_40905284/article/details/104423555