nyoj277 有趣的问题

本文介绍了一种利用迪杰斯特拉算法解决迷宫最短路径问题的方法。通过将迷宫抽象为图结构,并考虑墙壁障碍及门的位置,实现了从起点到终点的最短路径计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有趣的问题

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 4
描述
You are to find the length of the shortest path through a chamber containing obstructing walls. The chamber will always have sides at x = 0, x = 10, y = 0, and y = 10. The initial and final points of the path are always (0, 5) and (10, 5). There will also be from 0 to 18 vertical walls inside the chamber, each with two doorways. The figure below illustrates such a chamber and also shows the path of minimal length. 
输入
The input data for the illustrated chamber would appear as follows. 


4 2 7 8 9 
7 3 4.5 6 7 

The first line contains the number of interior walls. Then there is a line for each such wall, containing five real numbers. The first number is the x coordinate of the wall (0 < x < 10), and the remaining four are the y coordinates of the ends of the doorways in that wall. The x coordinates of the walls are in increasing order, and within each line the y coordinates are in increasing order. The input file will contain at least one such set of data. The end of the data comes when the number of walls is -1.
输出
The output should contain one line of output for each chamber. The line should contain the minimal path length rounded to two decimal places past the decimal point, and always showing the two decimal places past the decimal point. The line should contain no blanks.
样例输入
1
5 4 6 7 8
2
4 2 7 8 9
7 3 4.5 6 7
-1
样例输出
10.00
10.06
来源
黑书
上传者

苗栋栋

题意:

你需要找到从(0,5)到(10,5)的最短路径,在这着之中有墙阻隔,可以从墙的门过去(如图)。

输入第一行为墙的个数

第二行为五个实数,第一个为墙的横坐标,后面为墙中门两边的纵坐标。

思路:

拿到这个题,首先要知道这个题是一个全局最优问题,所以每一步求得最短的距离去相加得出结果一定wa。

所以要用到类似图里的最短路径算法(迪杰斯特拉算法)

所以现在的重点是要想把题目这种图转化为图,并在各点之间建立联系。这里需要用一个容器存所有点,另一个存所有边。具体见代码注释。

需要注意的一点是,一个点判断与其他点是否会被阻挡的时候,不仅要判断相邻列还要判断间隔列(求直线方程判断与线段是否相交)。

#include<bits/stdc++.h>
using namespace std;
struct node
{
    double x, y;
    int k;
};
struct node1{
    double y1, y2;
};//用来存所有阻碍墙

struct node2{
    double a, b, c, d, z ,e;
}te[1005];

bool cmp(node2 a, node2 b)
{
    return a.a < b.a;
}
vector<node> Ve[105];//申明node类型的邻接表
vector<node1> Vey[105];

double map1[105][105];//图
int kk;
double dis()//迪杰斯特拉算法思想
{
    double dis[105], minv = 99999.0;
    int vis[105], i, j, k;
    for(i = 1 ; i <= kk ; i++)
    {
        dis[i] = map1[1][i];
        vis[i] = 0;
    }
 //  printf("-->%0.2lf\n", dis[kk]);
    vis[1] = 1;
    for(i = 1 ; i < kk ; i++)
    {
        minv = 99999.0;
        for(j = 1 ; j <= kk ; j++)
        {
            if(vis[j] == 0 && dis[j] < minv)
            {
                k = j;
                minv = dis[j];
            }
        }
        vis[k] = 1;
        for(j = 1 ; j <= kk ; j++)
        {
            if(vis[j] == 0 && dis[j] > dis[k]+map1[k][j])
            {
              //  printf("aaa\n");
                dis[j] = dis[k]+map1[k][j];
            }
        }
    }
    return dis[kk];
}
int main()
{
    int n, i, j;
    //double num[20];
    while(~scanf("%d", &n))
    {
        if(n == -1)
           break;
        //memset(map, 0x3f3f3f3f, sizeof(map));
        for(i = 0 ; i < 105 ; i++)
        {
            Ve[i].clear();
            Vey[i].clear();
        }
        for(i = 0 ; i < 105 ; i++){
            for(j = 0 ; j < 105 ; j++){
                map1[i][j] = 99999.0;
            }
        }//全部初始化为最大值
        for(i = 0 ; i < 105 ; i++){
            map1[i][i] = 0;
        }//自己到自己距离为0
       // double a, b, c, d, e;
        int qk = 1, k1, zk, zi,z;
        kk=1;
        node ns;
        ns.x = 0;
        ns.y = 5;//起点
        ns.k = kk;
        kk++;
        Ve[1].push_back(ns);
        //num[qk] = 0;
        qk=2;
        for(i = 0 ; i < n ; i++){
            scanf("%lf %lf %lf %lf %lf", &te[i].a, &te[i].b, &te[i].c, &te[i].d, &te[i].e);
        }
        sort(te, te+n, cmp);    //按x坐标排序
        for(i = 0 ; i < n; i++)//构图
        {
            node na, nb, nc, nd;
           // scanf("%lf %lf %lf %lf %lf", &a, &b, &c, &d, &e);
            //num[qk] = a;
            na.x = te[i].a; na.y = te[i].b; na.k = kk; kk++;
            Ve[qk].push_back(na);

            nb.x = te[i].a; nb.y = te[i].c; nb.k = kk; kk++;
            Ve[qk].push_back(nb);

            nc.x = te[i].a; nc.y = te[i].d; nc.k = kk; kk++;
            Ve[qk].push_back(nc);

            nd.x = te[i].a; nd.y = te[i].e; nd.k = kk; kk++;
            Ve[qk].push_back(nd);

            node1 ya, yb, yc;//存一堵墙中不能过的部分
            ya.y1 = 0; ya.y2 = te[i].b;
            Vey[qk].push_back(ya);

            yb.y1 = te[i].c; yb.y2 = te[i].d;
            Vey[qk].push_back(yb);

            yc.y1 = te[i].e; yc.y2 = 10;
            Vey[qk].push_back(yc);
            // printf("%d\n", qk);
            qk++;
        }
        node la;
        la.x = 10; la.y = 5; la.k = kk;
        Ve[qk].push_back(la);//printf("-->%d\n", qk);
        qk++;//总墙数


        for(i = 1 ; i < qk-1 ; i++)
        {
            //printf("%d %d cc\n", i, Ve[i].size());
            for(j = 0 ; j < Ve[i].size() ; j++)
            {
                //printf("%d dd\n", i);
                for(k1 = 0 ; k1 < Ve[i+1].size() ; k1++)//判断相邻列
                {
                    double xx = (Ve[i][j].x-Ve[i+1][k1].x)*(Ve[i][j].x-Ve[i+1][k1].x);
                    double yy = (Ve[i][j].y-Ve[i+1][k1].y)*(Ve[i][j].y-Ve[i+1][k1].y);
                    double s = sqrt(xx+yy);
                    int be = Ve[i][j].k;
                    int en = Ve[i+1][k1].k;
                    // printf("-->%d %d %d %d %d\n",i+1,Ve[i+1].size(), k1, be, en);
                    map1[be][en] = map1[en][be] = s;
                }

               // printf("%d bb\n", i);
                for(k1 = i+2 ; k1 < qk ; k1++)//从当前点间隔一列开始判断
                {
                    //printf("aa\n");
                    for(zk = 0 ; zk < Ve[k1].size() ; zk++)
                    {

                        int flag = 0;
                        for(z = k1-1; z > i ; z--)
                        {
                            //double sy = (Ve[z][0].x-Ve[i][j].x)*1.0/(Ve[i][j].x-Ve[k1][zk].x)*(Ve[k1][zk].y-Ve[i][j].y)+Ve[i][j].y;
                           // printf("---->%0.2lf\n", sy);
                            double k = (Ve[i][j].y - Ve[k1][zk].y)/(Ve[i][j].x-Ve[k1][zk].x);
                            double b = Ve[i][j].y - k*Ve[i][j].x;
                            double sy = k*Ve[z][0].x+b;//先求出直线方程  判断y值位置来判断是否穿过墙
                            for(zi = 0 ; zi < Vey[z].size() ; zi++)
                            {
                                if(sy > Vey[z][zi].y1 && sy < Vey[z][zi].y2) //过不去
                                {
                                    flag = 1;
                                    break;
                                }
                            }
                            if(flag == 1)
                                break;
                        }

                        if(flag == 0)
                        {
                            double xx = (Ve[i][j].x-Ve[k1][zk].x)*(Ve[i][j].x-Ve[k1][zk].x);
                            double yy = (Ve[i][j].y-Ve[k1][zk].y)*(Ve[i][j].y-Ve[k1][zk].y);
                            double s = sqrt(xx+yy);
                            int be = Ve[i][j].k;
                            int en = Ve[k1][zk].k;
                            map1[be][en] = map1[en][be] = s;
                        }


                    }

                }
            }


        }
        /*for(i = 1 ; i <= kk ; i++){
            for(j = 1 ; j <= kk ; j++){
                printf("%0.2lf ", map[i][j]);
            }
            printf("\n");
        }
        printf("aaa\n");*/
        //printf("bb\n");
        double ans = dis();
        printf("%0.2lf\n", ans);
    }



    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值