hdu 2544 最短路

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544

题目描述:

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
Input

输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input

2 1

1 2 3

3 3

1 2 5

2 3 5

3 1 2

0 0

Sample Output

3

2

思路:spfa(spfa算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。)

具体思路在下方代码中有说明。

代码如下:

 

#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
#define mem(a, b) memset(a, b, sizeof(a))//这里是将数组a置为0,结合第49行看
using namespace std;
const int maxn = 10010, INF = 0x7fffffff;
int head[maxn], cnt, vis[maxn], d[maxn];//d[]的作用是用来标记结点对应的路径长度
int n, m;
struct node
{
    int u, v, w, next;//next的作用是用来寻找上一结点的权值,下方有介绍
}Node[maxn];

void add(int u, int v, int w)
{
    Node[cnt].u = u;//cnt是数组下标//结合第83行可知,第一次调用时下标为0
    Node[cnt].v = v;
    Node[cnt].w = w;
    Node[cnt].next = head[u];
    head[u] = cnt++;
}
//分析第20 21这两行代码的作用
/*
 //下方的u1,u2,u3仅是为了区分第几组的输入值,便于去理解
结合第83行,开始时head内每个值均为-1,所以
第一次调用add函数时:cnt=0.第20行:Node[0].next=head[u1],head[u1]=-1,即Node[0].next=-1;
                    第21行:head[u1]=0
                           这里u1的值是下方main函数内第一次输入的起始结点的值
             使用之后cnt自增为1
main函数中,i++
第二次调用add函数时:cnt=1.第20行:Node[1].next=head[u1],head[u1]=0
                       由上方已知,head[u1]已被刷新为0,
                        这里的0是当cnt=0时赋给head[u1]的值,这里的u1对应的值也是第一次输入的起始点的值;
                   第21行:head[u2]=1
                          这里的u2对应的是第二次输入的起始结点的值。
             使用之后cnt继续加1,变为2
main函数中,i++
第三次调用add函数时:cnt=2.第20行:Node[2].next=head[u2],head[u2]=2
                   第21行:head[u3]=2
             使用之后cnt=3
*/

void spfa(int s)//起点s
{
    queue<int> Q;
    for(int i=0; i<=n; i++) d[i] = INF;
    d[s] = 0;//起始点到起始点的距离为0
    mem(vis, 0);
    Q.push(s);//使起始点入队
    vis[s] = 1;//这里vis[]的作用不是用来判断是否标记的,而是用来判断是否在队列中,1表示在队列中,0表示不在
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        vis[u] = 0;//起始点已出队
        for(int i=head[u]; i!=-1; i=Node[i].next)
        /*这里for循环内的条件也很特殊
        i的初值为最后一组数据对应的起始点,通过不断找上一结点,来结束循环
        终止条件为i!=-1,由head[u1]=-1已知,第一组起始点对应的head值为-1,当找到-1时就代表已找到第一组结点值,结束
        i的变化条件是,i不断被赋予上一组的值
        */
        {
            node e = Node[i];//这里e的作用就是Node[maxn]的作用,为了简便换个名称
            //d[e.v]就相当于d[Node[i].v],同理适用于d[e.u]与e.w
            if(d[e.v] > d[e.u] + e.w)//d[e.v]表示0-v结点的长度,d[e.u]表示0-u结点的长度
                //这里是用来刷新最短路径的长度的
            {
                d[e.v] = d[e.u] + e.w;
                if(!vis[e.v])//起始设置均为0,如果不在队列中,就让其入队。入队操作在比较操作之后
                {
                    Q.push(e.v);//终点入队
                    vis[e.v] = 1;//表示已在队列之中
                }
            }
        }
    }
}

int main()
{
    while(cin>> n >> m && n+m)
    {
        mem(head, -1);//刷新
        cnt = 0;//刷新
        for(int i=1; i<=m; i++)//<m 因为输入的是几条路
        {
            int u, v, w;
            cin>> u >> v >> w;
            add(u, v, w);
            add(v, u, w);//无向图再加这一步
        }
        spfa(1);//由题意描述这里从1点开始,到n点结束,故输出的数组对应的是n
        cout<< d[n] <<endl;
    }

    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值