http://acm.hdu.edu.cn/showproblem.php?pid=2544
题意:中文题求最短路。无负值。
思路:主要是用来熟悉三种基本最短路算法。先来整体教程。总体而言,三种算法都是对点的不断松弛而找出最短路,而且最短路途中的任何节点都满足其为当前最短路。
1、dijkstra算法:给一个讲的比较好的博客,尤其是里面的动态图可以多看。核心就是两个for,第一个是找下一个最短路径点,第二个是以该点为第三节点对未访问节点进行松弛。当所有节点都进行完松弛操作后,路就不能比这更短了,即找到最短路。
2、floyd算法:如果说上面是没最优子结构的贪心,这里就是DP。开辟第三维数组代表进行松弛的第三节点。权值可以为负。
3、spfa算法:也是先给出博客,运用优先队列优化,复杂度大大降低但不稳定。还有注意点写在了注释。
给出的博客讲述的非常详细,这里不多赘述。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
const int N = 1000;
const int INF = 0x3f3f3f3f;
int dis[N], G[N][N], n, s;
bool vis[N];
void dijkstra()
{
for(int i = 1; i <= n; i++)
dis[i] = G[1][i];//代表起点到各个节点的距离
dis[1] = 0;
for(int i = 1; i <= n; i++)//这里也可以事先标记起点已访问,然后遍历n-1个节点
{
int k = -1;
for(int j = 1; j <= n; j++)
{
if(!vis[j] && (k==-1 || dis[j]<dis[k]))
k = j;
}
if(k == -1) break;//已经遍历所有的点
vis[k] = true;
for(int j = 1; j <= n; j++)
{
if(!vis[j]) dis[j] = min(dis[j], dis[k]+G[k][j]);
}
}
printf("%d\n", dis[n]);
}
void floyd()
{
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
G[i][j] = min(G[i][j], G[i][k]+G[k][j]);
printf("%d\n", G[1][n]);
}
void spfa()
{
queue<int>que;
for(int i = 1; i <= n; i++)
dis[i] = INF;//初值记得赋无穷,而不是G数组中的值!
dis[1] = 0;
vis[1] = true;
que.push(1);
while(!que.empty())
{
int now = que.front();
que.pop();
vis[now] = false;//记得还原!!
for(int i = 1; i <= n; i++)
{
if(dis[now]+G[now][i]<dis[i])
{
dis[i] = dis[now]+G[now][i];
if(!vis[i])
{
vis[i] = true;
que.push(i);
}
}
}
}
printf("%d\n", dis[n]);
}
int main()
{
// freopen("in.txt", "r", stdin);
int m, e, w;
while(~scanf("%d%d", &n, &m))
{
if(n == 0 && m == 0) break;
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(i == j) G[i][j] = 0;
else G[i][j] = INF;
}
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &s, &e, &w);
G[s][e] = G[e][s] = w;
}
// dijkstra();
// floyd();
spfa();
}
return 0;
}