POJ2387(最短路基础)

题目大意:n个点,m条边,求从第一个点到第n个点的最短路径,最基础的最短路问题,图论由于刚开始训练,还是把Dijkstra算法和SPFA算法对着书上的思路模拟了一边加深印象。边看代码边解释。
Dijkstra:(4172KB, 63ms)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 1000 + 5;
const int INF = 100000;
int vis[maxn], dis[maxn];
int a[maxn][maxn];
int m, n;

void dijkstra(int s)
{
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++) dis[i] = INF;
    dis[s] = 0;//初始化
    for (int i = 1; i <= n; i++) {
        int point = 0, mmin = INF;
        for (int j = 1; j <= n; j++) {
            if (!vis[j] && mmin > dis[j]) {
                mmin = dis[j];//找到离初始节点最近的点
                point = j;
            }
        }
        vis[point] = 1;//把该点也加到集合中
        for (int j = 1; j <= n; j++) {//更新未知点到已知点最近的距离
        //注意和最小生成树Prim算法的区别
            if (!vis[j] && dis[j] > dis[point] + a[point][j])
            {
                dis[j] = dis[point] + a[point][j];
            }
        }

    }

}
int main()
{
    //freopen("in", "r", stdin);
    cin >> m >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) a[i][j] = INF;//初始化
    for (int i = 0; i < m; i++) {
        int x, y, tmp;
        scanf("%d%d%d", &x, &y, &tmp);
        if (a[x][y] > tmp) {//这题的坑点就是可能有重边
            a[x][y] = a[y][x] = tmp;
        }
    }
    dijkstra(n);
    cout << dis[1] << endl;
    return 0;
}

SPFA:(284KB, 0ms)
个人认为较难理解的就是邻接表的构建与使用,我也是看着别人的用法,
指针,链表等知识的短板是硬伤啊。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int maxn = 1000 + 5;
const int INF = 1000000;
int vis[maxn], dis[maxn];
struct Eage {
    int to, w, next;
    //to:该点所到的点
    //w:该边的长
    //next:该边的下一个边
}eage[maxn*4];
int headlist[maxn];
int m, n;
void SPFA()
{
    for (int i = 1; i <= n; i++) dis[i] = INF;
    memset(vis, 0, sizeof(vis));
    dis[1] = 0;
    vis[1] = 1;
    //1:将所有dis[i]赋值为正无穷dis[0] = 0,将0进队
    queue<int> q;
    q.push(1);
    while (!q.empty()) {
        int v = q.front(); q.pop();
        vis[v] = 0;
    //2:对于出对的V,找到从V出发的所有边,然后松弛
        for (int i = headlist[v]; i != -1; i = eage[i].next) {
            if (dis[eage[i].to] > dis[v] + eage[i].w) {
                dis[eage[i].to] = dis[v] + eage[i].w;
                if (!vis[eage[i].to]) {
    //S到eage[i].to的距离变小,或许可以更新其他点的距离,若没有进队则入队
                    vis[eage[i].to] = 1;
                    q.push(eage[i].to);
                }
            }
        }
    }
    printf("%d\n", dis[n]);
}


int main()
{
    //freopen("in", "r", stdin);
    cin >> m >> n;
    for (int i = 1; i <= n; i++) headlist[i] = -1;
    for (int i = 1; i <= m*2; i+=2) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        eage[i].to = b;
        eage[i].w = c;
        eage[i].next = headlist[a];
        headlist[a] = i;//头插法

        eage[i+1].to = a;
        eage[i+1].w = c;
        eage[i+1].next = headlist[b];
        headlist[b] = i+1;
    }
    SPFA();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值