最短路径 1051

在一些美国主要城市里,为企业传送文件和小物品的自行车快递长期以来就是流动运输服务的一部分。波士顿的骑车人是不同寻常的一族。他们以超速、不遵守单行道和红绿灯、无视汽车、出租、公交和行人的存在而臭名远扬。快递服务竞争激烈。比利快递服务公司(BBMs)也不例外。为发展业务,制定合理的收费,BBMS正根据快递员能走的最短路线制定一项快递收费标准。而你则要替BBMS编写一个程序来确定这些路线的长度。

以下假设可以帮助你简化工作:

●快递员可以在地面上除建筑物内部以外的任何地方骑车。

●地形不规则的建筑物可以认为是若干矩形的合并。并规定,任何相交矩形拥有共同内部,而且是同一建筑物的一部分。

●尽管两个不同的建筑物可能非常接近,但永远不会重叠。(快递员可以从任意两个建筑物之间穿过。他们能够绕过最急的拐弯,可以贴着建筑物的边缘疾驶。)

●起点和终点不会落在建筑物内部。

●总有一条连接起讫点的线路。

 

 

题目主要按顺序判断   1,找出第四个点
                     2,点是否在矩形内不能走,
                     3,线段是否穿过矩形不能走,
                     4,最后广搜就好

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <math.h>
using namespace std;
#define eps 1e-8
struct point
{
   double x,y;
   int l,w;
}a[100][10],head,tail,head1,tail1,w1,w2,w3;
double c[100][10];
int T;
int add1;
double sum;
queue<point>q;
int  Fabs(double m)//精度
{
    if(fabs(m)<eps)
        return 0;
    else
        return m>0?1:-1;
}
int db(point l1,point l2)
{
    return l1.x==l2.x&&l1.y==l2.y;
}
double chaji(point p1,point p2)//叉积确定方向
{
   return p1.x*p2.y-p2.x*p1.y;
}
double len_x(point p1,point p2)
{
    return sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
double len_x1(point p1,point p2)
{
    return (p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y);
}
int bd2(point p3)//判断点是否 在矩形内部。
{
    int i,j;
    double sum;
    point p1,p2;
    for(i=0;i<T;i++)
    {
        sum=0;
        for(j=0;j<4;j++)
    {
        double a1,b1,c1;
        p1.x=a[i][j].x-p3.x;
        p1.y=a[i][j].y-p3.y;
        p2.x=a[i][j+1].x-p3.x;
        p2.y=a[i][j+1].y-p3.y;
         a1=len_x(a[i][j],p3);
         b1=len_x(p3,a[i][j+1]);
         c1=len_x(a[i][j+1],a[i][j]);
         sum+=Fabs(chaji(p1,p2))*acos((a1*a1+b1*b1-c1*c1)/(2.0*a1*b1));//角度*叉积=几何对点张开的角度,点角度如果2*PI,那么点就在几何内,反之则不在

    }
      sum=fabs(sum);//printf("%lf\n",sum);
        if(Fabs(sum-2.0*acos(-1.0))==0)点在矩形内
            {

                return 0;

            }
    }
    return 1;

}
int jd(point p1,point p2,point p3,point p4)
{
    point pt1,pt2,pt3,pp1,pp2,pp3;
    double l2,l3;
    if(db(p1,p3)||db(p2,p3)||db(p1,p4)||db(p2,p4))
    return 0;
    pt1.x=p2.x-p1.x;
    pt1.y=p2.y-p1.y;
    pt2.x=p3.x-p1.x;
    pt2.y=p3.y-p1.y;
    pt3.x=p4.x-p1.x;
    pt3.y=p4.y-p1.y;
    pp3.x=p2.x-p3.x;
    pp3.y=p2.y-p3.y;
    pp2.x=p1.x-p3.x;
    pp2.y=p1.y-p3.y;
    pp1.x=p4.x-p3.x;
    pp1.y=p4.y-p3.y;
    //l2=chaji(pt2,pt1)*chaji(pt1,pt3);
    //l3=chaji(pp2,pp1)*chaji(pp1,pp3);
    //if((l2==0&&l3!=0)||(l3==0&&l2!=0))
        //add1++;
    if(chaji(pt2,pt1)*chaji(pt1,pt3)>0&&chaji(pp2,pp1)*chaji(pp1,pp3)>0)//俩个叉积确定俩线段是否相交,
    return 1;
    return 0;
}
int bd(point p1,point p2)
{
       int i,j;
       for(i=0;i<T;i++)
        {
            for(j=0;j<4;j++)
        {
           if(jd(p1,p2,a[i][j],a[i][j+1]))
           return 0;

        }
         if(jd(p1,p2,a[i][0],a[i][2])||jd(p1,p2,a[i][1],a[i][3]))//多加俩条对角线判断线段是否穿过矩形
            return 0;
        }
        return 1;
}
void BFS()//最后广搜
{
    int i,j;
    while(!q.empty())
    {
        head=q.front();
        q.pop();
        for(i=0;i<=T;i++)
        for(j=0;j<4;j++)
           {
            head1=head;
            if(bd(head1,a[i][j])&&bd2(a[i][j]))
            {

              if(c[i][j]>c[head.l][head.w]+len_x(head,a[i][j]))当找到更近点便加点队列中
              {
              c[i][j]=c[head.l][head.w]+len_x(head,a[i][j]);
                  head1.x=a[i][j].x;
                  head1.y=a[i][j].y;
                  head1.l=i;
                  head1.w=j;
                  q.push(head1);
              }

            }
              if(T==i)
            j=10;
           }

    }

}

int main()
{
     int i,j;
     scanf("%d",&T);
     sum=10000;
     scanf("%lf%lf%lf%lf",&head.x,&head.y,&tail.x,&tail.y);
     for(i=0;i<T;i++)
     {
     for(j=0;j<3;j++)
     scanf("%lf%lf",&a[i][j].x,&a[i][j].y);
     w1=a[i][1];
     w2=a[i][2];
     w3=a[i][0];
    if(len_x1(w1,w2)==len_x1(w3,w1)+len_x1(w2,w3))//按顺序,找出矩形第四个点的位置,
        a[i][1]=w3,a[i][2]=w1,a[i][0]=w2;
    else if(len_x1(w2,w3)==len_x1(w3,w1)+len_x1(w2,w1))
    a[i][1]=w1,a[i][2]=w2,a[i][0]=w3;
     else if(len_x1(w1,w3)==len_x1(w3,w2)+len_x1(w2,w1))
       a[i][1]=w2,a[i][2]=w1,a[i][0]=w3;
     a[i][j].x=a[i][2].x-a[i][1].x+a[i][0].x;
     a[i][j].y=a[i][2].y-a[i][1].y+a[i][0].y;
     a[i][4].x=a[i][0].x;
     a[i][4].y=a[i][0].y;
     }
     a[T][0].x=tail.x;
     a[T][1].x=head.x;
     a[T][0].y=tail.y;
     a[T][1].y=head.y;
     while(!q.empty())
     q.pop();
     head1.x=head.x;
     head1.y=head.y;
     head1.l=T;
     head1.w=1;
     tail.l=T;
     tail.w=0;
     q.push(head1);
     for(i=0;i<=40;i++)
     for(j=0;j<=6;j++)
     c[i][j]=10000000;
     c[T][1]=0;
     BFS();
     printf("%.2lf\n",c[T][0]);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值