1003. Emergency (25)

本文详细介绍如何使用Dijkstra算法解决单源最短路径问题,并结合实际案例讲解如何求解最短路径长度、路径数量及最大救援队伍数量。文章还提供了完整的AC代码实现。

1. 原题链接

1003. Emergency (25)

2. 理解题目

图结点表示城市,点权表示每个城市的救援队伍数量,边权表示城市间的距离;给出”城市图”信息;
求出从起始城市(st)到终点城市(ed)的最短路径、最短路径条数和所能携带的救援队伍的最大数量;

3. 解题思路

[思路]
  1. 我们知道可以采用链表和数组的方式进行存储图信息,这里我们采用数组的方式;其中w[c1]表示城市c1的救援队伍数,即点权;dis[c1][c2]表示城市c1和c2之间路的距离,即边权;
  2. 求最短路劲,我们这里采用Dijkstra(单源最短路问题,即给出起点可以求到其他每个点的最短路径长,存储在d[]数组中);
  3. Dijkstra算法以起始点(st)作为参数,通过循环n次(总点数)把每个点都纳入最小路径的结果图中(即都访问到);

    具体求法是:1) 遍历找到距离已经访问的点最近的点(要求没有访问过) 2) 加以访问(vis[]变成true);3) 利用新加入的点去优化d[]数组;

4. 关键点

  1. 注意d[],dis[]的初始化最好采用&ltalgorithm&gt头文件中的fill函数;尤其是dis数组的初始化很容易易漏;

  2. 注意,

    scanf(“%d%d”,&c1,&c2);
    scanf(“%d”,&dis[c1][c2]);
    不可以写成scanf(“%d%d%d”,&c1,&c2,&dis[c1][c2]);
    emmm……这个赋值的用法我搞了很久也没明白,但是这样就是会错误; 以后还是老老实实分开写就好。要是谁搞清楚了,求指教~~~

5. AC代码

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

const int maxn=510;
const int INF=(1<<30)-1;//or INF=0x3fffffff
int dis[maxn][maxn];//边权 
int w[maxn];//点权
bool vis[maxn]={false};//都未访问 

int n,m;int s,e;//点数,边数,起始,终点 
int d[maxn],num[maxn],wsum[maxn];//求到每个点最短路长d[]、最短路条数num[]、最大点权和wsum[]

void Diks(int st){
    //初始化 
    fill(d,d+maxn,INF);d[st]=0;
    memset(num,0,sizeof(num));num[st]=1;
    memset(wsum,0,sizeof(wsum));wsum[st]=w[st];
//Dijkstra
    for(int i=0;i<n;i++){
    //找到最小的d[u]
        int u=-1,Min=INF;
        for(int j=0;j<n;j++){
            if(vis[j]==false&&d[j]<Min){
                u=j;Min=d[j];
            }
        }
        if(u==-1) return ;//剩下的不联通

    //访问 
    vis[u]=true;
    //利用新访问的点u去优化d[] 
    for(int j=0;j<n;j++){
        if(vis[j]==false&&dis[u][j]!=INF){//可以访问到且没有访问过 
            if(d[u]+dis[u][j]<d[j]){
                d[j]=d[u]+dis[u][j];//更新最短路长d[]
                num[j]=num[u];//继承num[u] 
                wsum[j]=wsum[u]+w[j]; //修改wsum[j]
            }else if(d[u]+dis[u][j]==d[j]){
                num[j]+=num[u];
                wsum[j]=wsum[j]>(wsum[u]+w[j])? wsum[j]:(wsum[u]+w[j]);
            }
        }
    }
    } 
}
int main(){
    //记录图信息 
    scanf("%d%d%d%d",&n,&m,&s,&e);
    for(int i=0;i<n;i++) scanf("%d",&w[i]);
    int c1,c2;
    fill(dis[0],dis[0]+maxn*maxn,INF);//易漏 
    for(int i=0;i<m;i++){
        scanf("%d%d",&c1,&c2);
        scanf("%d",&dis[c1][c2]);
        dis[c2][c1]=dis[c1][c2]; //易漏 
    }
    //Dijkstra法求最短路d[],同时求num[]、wsum[]
    Diks(s);//起始点作为参数 
    printf("%d %d\n",num[e],wsum[e]);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值