带权最短路问题

陌路散爱 提交于 2020-04-04 15:08:33

最短路之最大点权问题

问题引入:PTA A1003

问题分析:

直接分析输入输出。

输入

  1. 点数n、边数m、起点st、终点ed

  2. 点权

  3. 边权

输出

  1. 最短路条数
  2. 最短路里最大点权和

题解

最短路算法无非dijkstra、Floyd、SPFA,这里以dijkstra算法为例。

在dijkstra的基础上再引入三个数组:weg[],点权,w[]记录最大点权,way[]记录最短路条数。

下面分析dij()函数:

//邻接矩阵G[][],最短路数组dis[],访问数组vis[]
void dij(int st, int ed)//传入起点、终点
{
    //初始化(从0开始计数)
    for (int i = 0; i < n; ++i) {
        vis[i] = 0;
        w[i] = 0;
        dis[i] = G[st][i];
    }
    w[st] = weg[st];//起点的点权
    way[st] = 1;//起点到起点的路径为1
    dis[st] = 0;
    
    for (int i = 0; i < n; ++i) {
        int x = -1, mx = inf;
        for (int j = 0; j < n; ++j) {
            if (!vis[j] && dis[j] < mx) {
                x = j;
                m = dis[j];
            }
        }
        
        if (x == -1) return;//若x为-1,则该点与其他点都不联通。
        for (int j = 0; j < n; ++j)
            if (!vis[j] && G[x][j] != inf) {
                if (dis[j] == dis[x] + G[x][j]) { //走中转站和不走中转站都一样
                    //那就比点权
                    if (w[j] < w[x] + weg[j]) w[j] = w[x] + weg[j];
                    way[j] += way[x];	//再加上一条从中转站过来的路
                } else if (dis[j] > dis[x] + G[x][j]) {//可松弛
                    dis[j] = dis[x] + G[x][j];
                    way[j] = way[x];	//要走最短路必须走中转站,故直接覆盖。
                    w[j] = w[x] + weg[j];
                }
            }
    }
    printf("%d %d", way[ed], w[ed]);
}

一下为我的AC代码,与题解的命名不一致,有需者请悉知。

#include <iostream>
using namespace std;
const int inf = 1e7+7;
const int maxn = 505;
//w为邻接矩阵,n为点数,m为边数,dis为最短路
int w[maxn][maxn], n, m, dis[maxn];
//team为点权,tms记录最大点权和,way记录最短路径条数
int team[maxn], tms[maxn], way[maxn];
bool v[maxn];
void dij(int st, int end)
{
    for (int i = 0; i < n; ++i) {
        dis[i] = w[st][i];
        v[i] = 0;
        way[i] = 0;
    }
    dis[st] = 0;
    tms[st] = team[st];
    way[st] = 1;
    for (int i = 0; i < n; ++i) {
        int x = -1, mx = inf;
        for (int j = 0; j < n; ++j)
            if (!v[j] && dis[j] < mx) {
                x = j;
                mx = dis[j];
            }
        if (x == -1) return;
        v[x] = 1;
        for (int j = 0; j < n; ++j)
            if (!v[j] && w[x][j] != inf) {
                if (dis[j] == dis[x] + w[x][j]) {
                    if (tms[x] + team[j] > tms[j]) tms[j] = tms[x] + team[j];
                    way[j] += way[x];
                } else if (dis[j] > dis[x] + w[x][j]) {
                    dis[j] = dis[x] + w[x][j];
                    way[j] = way[x];
                    tms[j] = tms[x] + team[j];
                }
            }
    }
    printf("%d %d", way[end], tms[end]);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            w[i][j] = inf;
    int a, b ,c, st, end;
    cin >> st >> end;
    for (int i = 0; i < n; ++i) cin >> team[i];
    for (int i = 0; i < m; ++i) {
        cin >> a >> b >> c;
        w[a][b] = c;
        w[b][a] = c;
    }
    dij(st, end);
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!