《L2-001 紧急救援》(深度剖析)浅谈最短路

首先看这道题,我们需要去找到最短路.并且记录相同的最短路数,然后找到 最短路里人数最多的路打印它
作为一个蒟蒻,我只会最基本的最短路来找单点到各点的最短路.
我认知里的真正熟练掌握应该是完全明白这个算法思想,并且能够自己模改算法里的一些来实现自己的目的.
虽然这确实很难,但是我觉得在不断深入了解与使用后,就会对这个算法有一个更加深刻的理解。
再看这道题,普通的狄杰斯特拉算法貌似无法实现我们的目的。这个时候就需要我们来改变这个算法的一些细节。
我们需要增加几个部分:
1.我们在找最短路的时候,在过程中如果遇到与之前记录里某两点之间路径长度相同的.
我们就知道这是另一条最短路,因为我们可以用这条边来替换原来的边。
2.人数的记录其实我们只需要在最短路的过程中比较就可以了.
这里有几个注意点:
1.相同的最短路并不是找到几条路径相同那么简单。因为他是可以有多种选择的情况.
比如1->2 的最短路有3条,2->3的最短路有3条,那么1->3的最短路就有6条(注意是相加,不是相乘)
2.路径的打印我们用递归的方法,在我们找路径的过程中如果碰到多条最短路,我们要保存的前驱点应该
是人数最多的那条.

一些话:学了一段时间算法了,我觉得很多东西开始可能很难理解,就像这里的思路,可能看了有些人也
不一定很理解,但是看了代码后再慢慢体会,最后就可以领悟到其中的真谛!

#include
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 2*1e5+5;
const int M = 4005*4005;
#define pi acos(-1)
#define INF 1e9
#define INM INT_MIN
#define pb(a)  push_back(a)
#define mk(a,b) make_pair(a,b)
#define dbg(x) cout << "now this num is " << x << endl;
#define sd(ax) scanf("%d",&ax)
#define sld(ax) scanf("%lld",&ax)
#define sdd(ax,bx) scanf("%d %d",&ax,&bx)
#define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx)
#define pr(a) printf("%d\n",a)
#define plr(a) printf("%lld\n",a)
int n,m,s,d,a[505],cost[505][505],dis[505],peo[505],pre[505],temp[505];//pre记录前缀城市,temp记录重复路径
void djst(int x)
{
    for(int i=0;i<n;++i) dis[i] = INF;
    dis[x] = 0;
    pre[x] = -1;//根节点
    memset(peo,0,sizeof(peo));
    memset(temp,0,sizeof(temp));
    peo[x] = a[x];
    temp[x] = 1;
    priority_queue<pii,vector<pii>,greater<pii> > Q;
    Q.push(pii(0,x));
    while(!Q.empty())
    {
        int u = Q.top().second,d = Q.top().first;
        Q.pop();
        if(dis[u] < d) continue;
        for(int i=0;i<n;++i)
        {
            if(dis[i] > dis[u]+cost[u][i])
            {
                dis[i] = dis[u]+cost[u][i];
                peo[i] = peo[u]+a[i];
                pre[i] = u;
                temp[i] = temp[u];
                Q.push(pii(dis[i],i));
            }
            else if(u != i && dis[i] == dis[u]+cost[u][i])//最短路数量比较,注意到自己要去除
            {
                temp[i] += temp[u];
                if(peo[i] < peo[u]+a[i])//人数比较
                {
                    pre[i] = u;
                    peo[i] = peo[u]+a[i];
                }
            }
        }
    }
}
void Path(int x)//递归打印路径
{
    if(pre[x] != -1)
    {
        Path(pre[x]);
        printf(" %d",x);
    }
    else
    {
        printf("%d",x);
    }
}
int main()
{
    scanf("%d %d %d %d",&n,&m,&s,&d);
    for(int i=0;i<n;++i) sd(a[i]);
    for(int i=0;i<n;++i)
        for(int j=0;j<n;++j) cost[i][j] = i==j?0:INF;
    while(m--)
    {
        int x,y,z;
        sddd(x,y,z);
        cost[x][y] = cost[y][x] = z;
    }
    djst(s);
    printf("%d %d\n",temp[d],peo[d]);
    Path(d);
}

你可能感兴趣的:(《L2-001 紧急救援》(深度剖析)浅谈最短路)