最短路是指一个图状结构中点a到点b的最短距离,常用到两种算法来解题。
Dijkstra算法:
思想:
Dijkstra算法是利用贪心的思想,从已知的最短距离点开始,更新相邻顶点的最短距离,之后将这个点排除。用于单源最短路问题。
题目:
hdoj : http://acm.hdu.edu.cn/showproblem.php?pid=2066
思路:
这个题看似是多源的,但实际上只要把出发点设为0,出发点到相邻点距离为0即可。
AC代码:
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int M = 1010;
const int INF = 0xfffffff;
int road[M][M], d[M], ss[M], des[M];//以road[a][b]来表示点a到点b的距离(点b到点a为road[b][a]) d[i]来存储出发点到点i的最短距离 一直更新这个距离
bool vis[M];//vis来标记排除的点
void dijkstra()
{
while(1)//刚开始循环时只有起点符合条件,循环到后面符合条件的点都被标记了
{
int m = INF, dx;
for(int i = 0; i < M; i++)//寻找距离最短的点
if(!vis[i] && d[i] < m)
{
m = d[i];
dx = i;
}
if(m == INF)
break;
vis[dx] = true;
for(int i = 0; i < M; i++)
if(!vis[i])
d[i] = min(d[i], d[dx] + road[dx][i]);//更新到达与该点相邻的点的最短距离
}
}
main()
{
int t, s, p;
while(~scanf("%d %d %d", &t, &s, &p))
{
fill(vis, vis + M, 0);
fill(&road[0][0], &road[0][0] + M * M, INF);
fill(d, d + M, INF);
while(t--)
{
int a, b, time;
scanf("%d %d %d", &a, &b, &time);
road[a][b] = road[b][a] = min(time, road[a][b]);
}
for(int i = 0; i< s; i++)
{
scanf("%d", &ss[i]);
road[ss[i]][0] = road[0][ss[i]] = 0;
d[ss[i]] = 0;
}
for(int i = 0; i < p; i++)
scanf("%d", &des[i]);
d[0] = 0;
dijkstra();
int res = INF;
for(int j = 0; j < p; j++)
res = min(res, d[des[j]]);
printf("%d\n", res);
}
}
利用动态规划的思想,计算经过点i到点j之间的路径,特点是代码十分好写,并且其结果是图中所有相连点的任意两点间的最短距离,但是耗时很长,时间复杂度为O(n ^ 3)。
题目:
hdoj : http://acm.hdu.edu.cn/showproblem.php?pid=2544
思路:
这道题数据范围并不大,可以漂亮地用Floyd算法解决。注意距离是无向的,要正反赋值。
AC代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int M = 110;
int len[M][M];//len[a][b]记录点a到点b的有向距离
main()
{
int n, m;
while(~scanf("%d %d", &n, &m))
{
if(n == 0 && m == n)
break;
for(int i = 0; i < M; i++)
for(int j = 0; j < M; j++)
len[i][j] = 999999;
while(m--)
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
len[a][b] = c;
len[b][a] = c;
}
len[1][1] = 0;
for(int k = 1; k < M; k++)//中间点
for(int i = 1; i < M; i++)//起始点
for(int j = 1; j < M; j++)//终点 顺序不能乱
len[i][j] = min(len[i][j], len[i][k] + len[k][j]);
printf("%d\n", len[1][n]);
}
}
Dijkstra算法可以用堆对其优化,以下是2544用堆优化的Dijkstra算法AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 1e9;
const int M = 110;
int n, m, d[M][M], l[M];
typedef pair <int, int> P;
priority_queue<P, vector<P>, greater<P> > q;
void dijstra()
{
while(!q.empty())
q.pop();
q.push(P(0, 1));
while(!q.empty())
{
P p = q.top();
q.pop();
if(l[p.second] < p.first)
continue;
for(int i = 2; i < M; i++)
if(d[p.second][i] != INF && l[i] > l[p.second] + d[p.second][i])
{
l[i] = l[p.second] + d[p.second][i];
q.push(P(l[i], i));
}
}
}
main()
{
while(~scanf("%d %d", &m, &n))
{
fill(&d[0][0], &d[0][0] + M * M, INF);
fill(l, l + M, INF);
if(m == n && m == 0)
break;
l[1] = 0;
for(int i = 0; i < n; i++)
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
d[a][b] = d[b][a] = min(d[a][b], c);
}
dijstra();
cout << l[m] << endl;
}
}