1. 原题链接
2. 理解题目
图结点表示城市,点权表示每个城市的救援队伍数量,边权表示城市间的距离;给出”城市图”信息;
求出从起始城市(st)到终点城市(ed)的最短路径、最短路径条数和所能携带的救援队伍的最大数量;
3. 解题思路
[思路]
- 我们知道可以采用链表和数组的方式进行存储图信息,这里我们采用数组的方式;其中w[c1]表示城市c1的救援队伍数,即点权;dis[c1][c2]表示城市c1和c2之间路的距离,即边权;
- 求最短路劲,我们这里采用Dijkstra(单源最短路问题,即给出起点可以求到其他每个点的最短路径长,存储在d[]数组中);
Dijkstra算法以起始点(st)作为参数,通过循环n次(总点数)把每个点都纳入最小路径的结果图中(即都访问到);
具体求法是:1) 遍历找到距离已经访问的点最近的点(要求没有访问过) 2) 加以访问(vis[]变成true);3) 利用新加入的点去优化d[]数组;
4. 关键点
注意d[],dis[]的初始化最好采用<algorithm>头文件中的fill函数;尤其是dis数组的初始化很容易易漏;
注意,
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;
}
本文详细介绍如何使用Dijkstra算法解决单源最短路径问题,并结合实际案例讲解如何求解最短路径长度、路径数量及最大救援队伍数量。文章还提供了完整的AC代码实现。

1271

被折叠的 条评论
为什么被折叠?



