SDUT 2143 图结构练习——最短路径

本文提供了几种经典的图算法实现,包括Flyod、Dijkstra、Bellman-Ford及其优化版和SPFA算法,通过C++代码详细展示了如何求解单源最短路径问题。

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

点击打开题目链接

//Flyod
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

int Edge[10010][10010];

int main()
{
    int n, m;
    while(cin >> n >> m, n&&m)
    {
        for(int i = 1; i<=n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
             (i == j) ? Edge[i][j] = 0 : Edge[i][j] = INF;
            }
        }
        while(m--)
        {
            int u, v, w;
            cin >> u >> v >> w;
            if(Edge[u][v] > w)
            Edge[u][v] = Edge[v][u] = w;
        }
        for(int k = 1; k <= n; k++)
        {
            for(int i = 1; i <= n; i++)
            {
                if(Edge[i][k] != INF)
                {
                    for(int j = 1; j <= n; j++)
                    {
                        Edge[i][j] = min(Edge[i][k]+Edge[k][j], Edge[i][j]);
                    }
                }
            }
        }
        cout <<  Edge[1][n] << endl;
    }
    return 0;
}

//Dijkstra
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

int Edge[110][110];
int path[110];//路径记录(需要时记录)
int dis[110];
bool vis[110];
int n, m;

void Dijkstra(int st);

int main()
{
    while(cin >> n >> m)
    {
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                (i == j) ? Edge[i][j] = 0 : Edge[i][j] = INF;
            }

        }
        int u, v, w;
        while(m --)
        {
            cin >> u >> v >> w;
            if(Edge[u][v] > w)
            {
                Edge[u][v] = Edge[v][u] = w;
            }
        }
        Dijkstra(1);
    }
    return 0;
}


void Dijkstra(int st)
{

    for(int i = 1; i <= n; i++)
    {
        dis[i] = Edge[st][i];//源点到每个顶点的最短路径的长度
        if(i != st && dis[i] < INF)
        {
            path[i] = st;
        }
        else
        {
            path[i] = -1;
        }
    }
    vis[st] = 1, dis[st] = 0;
    for(int i = 1; i < n; i++)//从顶点st确定n-1条最短路径
    {
        int tmp = INF, pos;
        for(int j = 1; j <= n; j++)
        {
            if(!vis[j] && dis[j] < tmp)//选择具有最短路径的顶点pos
            {
                tmp = dis[pos = j];
            }
        }
        vis[pos] = 1;
        for(int k = 1; k <= n; k++)//修改剩下未访问顶点的dis
        {
            if(!vis[k] && Edge[pos][k] < INF && dis[pos]+Edge[pos][k] < dis[k])
            {
            dis[k] = min(dis[k], Edge[pos][k]+dis[pos]);
            path[k] = pos;
            }
        }
    }
    cout << dis[n] << endl;
}


//Bellman-Ford
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

int n, m;
//int path[110];
int Edge[110][110];
int dis[110];

void Bellman_Ford(int st);

int main()
{
    while(cin >> n >> m)
    {
        memset(Edge, INF, sizeof(Edge));
        while(m --)
        {
            int u, v, w;
            cin >> u >> v >> w;
            if(Edge[u][v] > w)
            {
                Edge[u][v] = Edge[v][u] = w;
            }
        }
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                if(i == j)
                {
                    Edge[i][j] = 0;
                }
                else if(Edge[i][j] == 0)
                {
                    Edge[i][j] = INF;
                }
            }
        }
        Bellman_Ford(1);

    }
    return 0;
}


void Bellman_Ford(int st)
{
    for(int i =  1; i <= n; i++)
    {
        dis[i] = Edge[st][i];//初始化经过一条边的dis[u]的值就是Edge[st][u]
    }
     for(int k = 2; k <= n-1; k++)//经过k条边到达点u,修改dis(1)[u]递归出dis(2)[u],....dis(n-1)[u]
    {//dis(1)[u]表示经过1边到u的最短距离,...dis(n-1)[u]表示经过n-1条边到u的最短距离
   //假设a -> c 被 a -> b -> c路径dis更新后,也许会出现d使得a -> b -> d -> c的距离dis更短
         for(int u = 1; u <= n; u++)//修改每个顶点的dis[u]
        {
            if(u != st)
            {
                for(int j = 1; j <= n; j++)//考虑其他顶点
                {
                    if(Edge[j][u] < INF && dis[j] + Edge[j][u] < dis[u])//顶点j到顶点u有直接路径,且途径顶点j可以是的dis[u]缩短
                    {
                        dis[u] = dis[j] + Edge[j][u];
                    }
                }
            }
        }
    }
    cout << dis[n] << endl;
}


//Bellman-Ford优化
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

struct edge
{
  int u, v, w;
}Edge[101000];

int n, m;
int dis[1010];

void Bellman_Ford(int st);

int main()
{
    while(cin >> n >> m)
    {
        memset(Edge, INF, sizeof(Edge));
        for(int i = 1; i <= m; i++)
        {
            int u, v, w;
            cin >> u >> v >> w;
            Edge[i].u = u, Edge[i].v = v , Edge[i].w = w;
            Edge[i+m].u = v, Edge[i+m].v = u , Edge[i+m].w = w;//无向图
        }
        Bellman_Ford(1);
    }
    return 0;
}


void Bellman_Ford(int st)
{
    for(int i =  1; i <= n; i++)
    {
        dis[i] = INF;
    }
    dis[st] = 0;
    for(int k = 2; k <= n; k++)
    {
        for(int i = 1; i <= 2*m; i++)
        {
        if(dis[Edge[i].u] != INF  &&  dis[Edge[i].u] + Edge[i].w < dis[Edge[i].v])
                        dis[Edge[i].v] = dis[Edge[i].u] + Edge[i].w;
        }
    }
    cout << dis[n] << endl;
}


//SPFA
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

int Edge[110][110];
int n, m;
int flag, ans;

queue<int > Q;
bool vis[110];
int dis[110];

void SPFA(int st);

int main()
{
    int u, v, w;
    while(~scanf("%d %d", &n, &m))
    {
        memset(Edge, INF, sizeof(Edge));
        while(m --)
        {
            scanf("%d %d %d", &u,  &v,  &w);
            if(Edge[u][v] > w)
            {
              Edge[u][v] = Edge[v][u] = w;
            }
        }
        SPFA(1);
    }
    return 0;
}

void SPFA(int st)
{
    int tmp;
    memset(dis, INF, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    vis[st] = 1, dis[st] = 0;
    Q.push(st);
    while(!Q.empty())
    {
        tmp = Q.front();
        Q.pop();
        vis[tmp] = 0;
        for(int i = 1; i <= n; i++)
        {
          if(Edge[tmp][i] < INF && dis[tmp] + Edge[tmp][i] < dis[i])
          {
            dis[i] = dis[tmp] + Edge[tmp][i];
            if(!vis[i])
            {
              vis[i] = 1;
             Q.push(i);
            }
          }
        }
    }
    printf("%d\n", dis[n]);
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值