题目大意:n个点,m条边,求从第一个点到第n个点的最短路径,最基础的最短路问题,图论由于刚开始训练,还是把Dijkstra算法和SPFA算法对着书上的思路模拟了一边加深印象。边看代码边解释。
Dijkstra:(4172KB, 63ms)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1000 + 5;
const int INF = 100000;
int vis[maxn], dis[maxn];
int a[maxn][maxn];
int m, n;
void dijkstra(int s)
{
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++) dis[i] = INF;
dis[s] = 0;//初始化
for (int i = 1; i <= n; i++) {
int point = 0, mmin = INF;
for (int j = 1; j <= n; j++) {
if (!vis[j] && mmin > dis[j]) {
mmin = dis[j];//找到离初始节点最近的点
point = j;
}
}
vis[point] = 1;//把该点也加到集合中
for (int j = 1; j <= n; j++) {//更新未知点到已知点最近的距离
//注意和最小生成树Prim算法的区别
if (!vis[j] && dis[j] > dis[point] + a[point][j])
{
dis[j] = dis[point] + a[point][j];
}
}
}
}
int main()
{
//freopen("in", "r", stdin);
cin >> m >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) a[i][j] = INF;//初始化
for (int i = 0; i < m; i++) {
int x, y, tmp;
scanf("%d%d%d", &x, &y, &tmp);
if (a[x][y] > tmp) {//这题的坑点就是可能有重边
a[x][y] = a[y][x] = tmp;
}
}
dijkstra(n);
cout << dis[1] << endl;
return 0;
}
SPFA:(284KB, 0ms)
个人认为较难理解的就是邻接表的构建与使用,我也是看着别人的用法,
指针,链表等知识的短板是硬伤啊。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1000 + 5;
const int INF = 1000000;
int vis[maxn], dis[maxn];
struct Eage {
int to, w, next;
//to:该点所到的点
//w:该边的长
//next:该边的下一个边
}eage[maxn*4];
int headlist[maxn];
int m, n;
void SPFA()
{
for (int i = 1; i <= n; i++) dis[i] = INF;
memset(vis, 0, sizeof(vis));
dis[1] = 0;
vis[1] = 1;
//1:将所有dis[i]赋值为正无穷dis[0] = 0,将0进队
queue<int> q;
q.push(1);
while (!q.empty()) {
int v = q.front(); q.pop();
vis[v] = 0;
//2:对于出对的V,找到从V出发的所有边,然后松弛
for (int i = headlist[v]; i != -1; i = eage[i].next) {
if (dis[eage[i].to] > dis[v] + eage[i].w) {
dis[eage[i].to] = dis[v] + eage[i].w;
if (!vis[eage[i].to]) {
//S到eage[i].to的距离变小,或许可以更新其他点的距离,若没有进队则入队
vis[eage[i].to] = 1;
q.push(eage[i].to);
}
}
}
}
printf("%d\n", dis[n]);
}
int main()
{
//freopen("in", "r", stdin);
cin >> m >> n;
for (int i = 1; i <= n; i++) headlist[i] = -1;
for (int i = 1; i <= m*2; i+=2) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
eage[i].to = b;
eage[i].w = c;
eage[i].next = headlist[a];
headlist[a] = i;//头插法
eage[i+1].to = a;
eage[i+1].w = c;
eage[i+1].next = headlist[b];
headlist[b] = i+1;
}
SPFA();
return 0;
}