poj 1556 线段相交 + 最短路

这道题思路很简单,但是不知道为什么我实现的时候觉得极其恶心……于是憋了一天一夜,终于憋出来了,心情舒畅

题解:

很明显我们最后要跑的是最短路,所以现在的目标是构建一个无向\有向图(随意有无向)

图的构建:枚举起点 + 终点 + 题目给出的所有点 之间的任意两点间是否存在路径。枚举的时候还要判断这条边是否被堵。

最后就是跑一遍最短路

关于实现:

主要就是建图的问题。我为了方便自己理解分别弄了  一个door数组用来存所有的门  以及  一个point数组来存所有的点。

door数组的头和尾分别弄成x=0和x=10的整堵墙(即把(0,0)(0,10)当做一个门,(10,0)(10,10)也当做一个门,并且分别存两次(因为每一列正常有两道门))

在枚举的时候,从左至右枚举点,注意如果两点在同一列的时候就跳出,直接赋值为无穷。还有当起点为0的时候则无视刚刚那个规则。

上面还有一大堆模板。


#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
#define infinity 1e20       //模板begin
#define EP 1e-10
const int Max = 50;
const int MAXV = 300 ;
const double PI = 2.0*asin(1.0); //高精度求PI
struct Lpoint
{
    double x,y;
} point[Max<<2]; //点
struct Llineseg
{
    Lpoint a,b;
} door[Max][2]; //线段
struct Ldir
{
    double dx,dy;
}; //方向向量
struct Lline
{
    Lpoint p;
    Ldir dir;
}; //直线
struct Lrad
{
    Lpoint Sp;
    Ldir dir;
}; //射线
struct Lround
{
    Lpoint co;
    double r;
};//圆

double p2pdis(Lpoint p1,Lpoint p2)
{
    return (sqrt((p1.x-p2.x) * (p1.x-p2.x) +
                 (p1.y-p2.y) * (p1.y-p2.y)));
}

double xmulti(Lpoint p1,Lpoint p2,Lpoint p0)
{
    return((p1.x-p0.x) * (p2.y-p0.y) -
           (p2.x-p0.x) * (p1.y-p0.y));
}

double mx(double t1,double t2)
{
    if(t1>t2) return t1;
    return t2;
}
double mn(double t1,double t2)
{
    if(t1<t2) return t1;
    return t2;
}
int lsinterls(Llineseg u,Llineseg v)
{
    return( (mx(u.a.x,u.b.x)>=mn(v.a.x,v.b.x))&&
            (mx(v.a.x,v.b.x)>=mn(u.a.x,u.b.x))&&
            (mx(u.a.y,u.b.y)>=mn(v.a.y,v.b.y))&&
            (mx(v.a.y,v.b.y)>=mn(u.a.y,u.b.y))&&
            (xmulti(v.a,u.b,u.a)*xmulti(u.b,v.b,u.a)>=0)&&
            (xmulti(u.a,v.b,v.a)*xmulti(v.b,u.b,v.a)>=0));
}

int ponls(Llineseg l,Lpoint p)
{
    return( (xmulti(l.b,p,l.a)==0) &&
            ( ((p.x-l.a.x)*(p.x-l.b.x)<0 ) ||
              ((p.y-l.a.y)*(p.y-l.b.y)<0 )) );
}

int Euqal_Point(Lpoint p1,Lpoint p2)
{
    return((fabs(p1.x-p2.x)<EP)&&(fabs(p1.y-p2.y)<EP));
}

int lsinterls_A(Llineseg u,Llineseg v)
{
    return((lsinterls(u,v)) && (!Euqal_Point(u.a,v.a))&&
           (!Euqal_Point(u.a,v.b)) &&
           (!Euqal_Point(u.b,v.a))&&
           (!Euqal_Point(u.b,v.b)));
}
						//模板end
double Edge[Max<<2][Max<<2];
//Llineseg line[Max][Max<<2];
//int Num_line[Max];
void Make_line(int n)
{
//    memset(Num_line, 0, sizeof(Num_line));
    Llineseg tem;
    for(int i=0; i<=n; i++)//begin point
    {
        for(int j=i; j<=n; j++)//end point
        {
            if(i!=0 && (i+3)/4 == (j+3)/4) //(x+3)/4 代表该点所的墙的列数 如输入数据为2,则这组数据一共有4列墙(+起点和终点)
            {
                Edge[i][j] = Edge[j][i] = 1e8;
                continue;
            }
            tem.a = point[i];
            tem.b = point[j];
            int vis = 0;
            for(int k=(i+3)/4; k<=(j+3)/4; k++)//blocks
            {
                for(int l=0; l<2 && k!=(j+3)/4; l++)
                {
//                    if(lsinterls_A(tem,line[k][l]))
                    double tem_judge = xmulti(tem.a, tem.b, door[k][l].a) * xmulti(tem.a ,tem.b, door[k][l].b);
                    if(tem_judge < 0 || fabs(tem_judge) < 1e-6)
                        break;
                    else if(l==1)
                    {
                        vis = 1;
                        break;
                    }
                }
                if(vis) k = (j+3)/4;
                if(k==(j+3)/4)
                {
                    if(!vis)Edge[i][j] = Edge[j][i] = p2pdis(point[i], point[j]);
                    else
                        Edge[i][j] = Edge[j][i] = 1e8;
                }
            }
        }
    }
}


bool vis[Max<<2];
double dist[Max<<2];
void dijkstra(int num, int u0)
{
    memset(vis, 0 ,sizeof(vis));
    for(int i=0; i<=num; i++)
        dist[i] = Edge[u0][i];
    vis[u0] = true;
    dist[u0] = 0;
    for(int i=1; i<=num; i++)
    {
        int tem_min = 1e8;
        for(int j=0; j<=num; j++)
        {
            if((u0!=0 && (u0-1)/4 == (j-1)/4) || u0 == j) continue;
            if(!vis[j] && dist[j] < tem_min)
            {
                tem_min = dist[j];
                u0 = i;
            }
        }
        vis[u0] = true;
        for(int j=0; j<=num; j++)
        {
//            if((u0!=0 && (u0-1)/4 == (j-1)/4) || u0 == j) continue;
            if(!vis[j] && dist[u0] + Edge[u0][j] < dist[j])
                dist[j] = Edge[u0][j] + dist[u0];
        }
    }
}



int main()
{
//    freopen("1556.txt","r",stdin);
    int n;
    while(~scanf("%d",&n) && n!=-1)
    {
        memset(Edge, 0, sizeof(Edge));
        for(int i=1; i<=n; i++)
        {
            double x;
            scanf("%lf",&x);
            scanf("%lf %lf %lf %lf",&door[i][0].a.y,
                  &door[i][0].b.y, &door[i][1].a.y,
                  &door[i][1].b.y);
            door[i][0].a.x = door[i][0].b.x =
            door[i][1].a.x = door[i][1].b.x = x;

            point[4*(i-1)+1].y = door[i][0].a.y;
            point[4*(i-1)+2].y = door[i][0].b.y;
            point[4*(i-1)+3].y = door[i][1].a.y;
            point[4*(i-1)+4].y = door[i][1].b.y;
            point[4*(i-1)+1].x = point[4*(i-1)+2].x = point[4*(i-1)+3].x = point[4*(i-1)+4].x = x;
        }
        //起点终点开口初始化
        door[0][0].a.x = door[0][0].a.y = 0;
        door[0][0].b.x = 0;
        door[0][0].b.y = 10;
        door[0][1].a = door[0][0].a;
        door[0][1].b = door[0][0].b;

        door[n+1][0].a.x = 10;
        door[n+1][0].a.y = 0;
        door[n+1][0].a.x = 10;
        door[n+1][0].a.y = 10;
        door[n+1][1].a = door[n+1][0].a;
        door[n+1][1].b = door[n+1][0].b;

        point[0].x = 0;
        point[0].y = 5;
        point[4*n+1].x = 10;
        point[4*n+1].y = 5;

        Make_line(4*n+1);
        dijkstra(4*n + 1, 0);
        printf("%.2lf\n",dist[4*n + 1]);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值