认为起始点编号为 0, 到临近点的距离为 0, 终点编号为 n, 到目标点的距离为 0
找 到各个目标点的最短距离 中 最小的 即 找 0 到 n 的最短路
dijkstra 适用于正权
算法思想:
把初始点看做一个集, 从 这个集里未遍历过的点中到初始点最近的点向外扩张,把它能接触到的点加到集里, 并更新初始点到这些点的距离
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 1006;
const int inf = 0x3f3f3f3f;
int ansdis[N], dis[N][N], vis[N];
int n, T, S, D, a, b, time;
void init() //初始化
{
int i, j;
for(i = 0; i < N; ++i)
for(j = 0; j < N; ++j)
dis[i][j] = inf;
for(i = 0; i < N; ++i)
dis[i][i] = 0;
ansdis[0] = 0;
for(i = 1; i <= T; ++i) //起始点和用时
{
scanf("%d%d%d", &a, &b, &time);
if(dis[a][b] > time) //可能有重复边
dis[a][b] = dis[b][a] = time;
n = max(n, max(a, b)); //记录点的最大的编号
}
++n;
for(i = 0; i < S; ++i)
{
scanf("%d", &a);
dis[0][a] = dis[a][0] = 0;
}
for(i = 0; i < D; ++i)
{
scanf("%d", &a);
dis[n][a] = dis[a][n] = 0;
}
}
void dijkstra()
{
int i, j;
for(i = 0; i < N; ++i)
{
ansdis[i] = dis[0][i]; //初始化,如果求 x 到 y 的最短路,这里初始化为 ansdis[x] = dis[x][i] ,最后答案输出 ansdis[y]
vis[i] = 0;
}
for(i = 0; i <= n; ++i)
{
int k, minn;
k = 0;
minn = inf;
for(j = 0; j <= n; ++j)
{
if(!vis[j] && ansdis[j] < minn)
{
minn = ansdis[j];
k = j; //找集合里未向外扩展(未遍历)的点中 到初始点最近的点
}
}
if(min == inf) //没有可以向外扩展的点
break;
vis[k] = 1;
for(j = 0; j <= n; ++j)
if(ansdis[j] > ansdis[k]+dis[k][j])
ansdis[j] = ansdis[k]+dis[k][j]; //由这个点向外扩张,更新各点到初始点的距离
}
}
int main()
{
while(~scanf("%d%d%d", &T, &S, &D))
{
n = 0;
init();
dijkstra();
printf("%d\n", ansdis[n]);
}
return 0;
}