解题报告 之 HDU2544 最短路
Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
Sample Output
3 2
题目大意:有n个几点1~n,m条双向边。求节点1到节点n的最短路。
分析:这道题是刚学习了SPFA来试试模版是否正确的。其实就是裸的单源最短路。(甚至用Floyd也能过),这里给出三种实现方法,主要是存一下模板,分别为Dijkstra、Floyd 和 SPFA。想学习SPFA的同学可以参照另一篇博文《SPFA算法详解》,我觉得讲的很详细。
上代码:
SPFA算法:求单源最短路,可判断有无负权回路。
#include<iostream>
#include<deque>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 110;
const int MAXM = 10100;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, next;
};
Edge edge[MAXM];
int head[MAXN];
int path[MAXN];
int inqueue[MAXN];
int dist[MAXN];
int viscnt[MAXN];
int cnt;
void addedge( int from, int to, int cap )
{
edge[cnt].from = from;
edge[cnt].to = to;
edge[cnt].cap = cap;
edge[cnt].next = head[from];
head[from] = cnt++;
}
int relax(int u,int v,int c)
{
if (dist[u] + c < dist[v])
{
dist[v] = dist[u] + c;
return 1;
}
return 0;
}
bool SPFA( int src, int n )
{
deque<int> dq;
memset( viscnt, 0, sizeof viscnt );
memset( inqueue, 0, sizeof inqueue );
memset( dist, INF, sizeof dist );
memset( path, -1, sizeof path );
inqueue[src] = 1;
viscnt[src]++;
dist[src] = 0;
dq.push_back( src );
while (!dq.empty())
{
int u = dq.front();
dq.pop_front();
inqueue[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(dist[u] < INF&&relax( u, v, edge[i].cap ))
{
path[v] = u;
if(!inqueue[v])
{
inqueue[v] = 1;
viscnt[v]++;
if(viscnt[v] == n) return false;
if(!dq.empty() && dist[v] <= dist[dq.front()])
dq.push_front( v );
else
dq.push_back( v );
}
}
}
}
return true;
}
int main()
{
int n,m;
while(cin >> n >> m &&n&&m)
{
memset( head, -1, sizeof head );
cnt = 0;
for(int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
addedge( a, b, c );
addedge( b, a, c );
}
SPFA( 1, n );
cout << dist[n] << endl;
}
return 0;
}
Dijkstra:求单源最短路径。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 200;
const int MAXM = 40000;
const int INF = 0x3f3f3f3f;
int map[MAXN][MAXN];
bool vis[MAXN];
int dist[MAXN];
void Dijkstra( int src, int n )
{
memset( vis, 0, sizeof vis );
memset( dist, INF, sizeof dist );
dist[src] = 0;
int next;
for(int i = 1; i <= n; i++)
{
int MIN = INF;
for(int j = 1; j <= n; j++)
{
if(!vis[j] && dist[j] < MIN)
{
MIN = dist[j];
next = j;
}
}
if(MIN == INF) break;
vis[next] = 1;
for(int j = 1; j <= n; j++)
{
if(!vis[j] && dist[next] + map[next][j] < dist[j])
{
dist[j] = dist[next] + map[next][j];
}
}
}
}
int main()
{
int n, m;
while(cin >> n >> m&&n&&m)
{
memset( map, INF, sizeof map );
for(int i = 1; i <= n; i++)
map[i][i] = 0;
int a, b, c;
for(int i = 1; i <= m; i++)
{
cin >> a >> b >> c;
map[a][b] = map[b][a] = c;
}
Dijkstra( 1, n );
cout << dist[n] << endl;
}
}
Floyd:求全源最短路。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 200;
const int INF = 0x3f3f3f3f;
int dist[MAXN][MAXN];
void Floyd( int n )
{
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n;i++)
for(int j = 1; j <= n; j++)
if(dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
int main()
{
int n, m;
while(cin >> n >> m&&n&&m)
{
memset( dist, INF, sizeof dist );
for(int i = 1; i <= n; i++)
dist[i][i] = 0;
int a, b, c;
for(int i = 1; i <= m; i++)
{
cin >> a >> b >> c;
dist[a][b] = dist[b][a] = c;
}
Floyd( n );
cout << dist[1][n] << endl;
}
return 0;
}
Bellman_Ford算法:求单源最短路判断有无负权回路。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 200;
const int MAXM = 40000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from, to, cap;
};
Edge edge[MAXM];
int dist[MAXN];
int pre[MAXN]; //用于打印路径
int cnt;
void addedge( int from, int to, int cap )
{
edge[cnt].from = from;
edge[cnt].to = to;
edge[cnt].cap = cap;
cnt++;
}
bool Bellman_Ford(int src, int n, int m )
{
memset( dist, INF, sizeof dist );
dist[src] = 0;
for(int i = 0; i < n-1; i++)
for(int j = 0; j < m; j++)
if(dist[edge[j].from] + edge[j].cap < dist[edge[j].to])
{
dist[edge[j].to] = dist[edge[j].from] + edge[j].cap;
pre[edge[j].to] = edge[j].from;
}
bool flag = true;
for(int i = 1; i <= m; i++)
{
if(dist[edge[i].from] + edge[i].cap < dist[edge[i].to])
{
flag = true;
break;
}
}
return flag;
}
int main( )
{
int n, m;
while(cin >> n >> m&&n&&m)
{
cnt = 0;
int a, b, c;
for(int i = 1; i <= m; i++)
{
cin >> a >> b >> c;
addedge( a, b, c );
addedge( b, a, c );
}
Bellman_Ford(1, n, 2 * m );
cout << dist[n] << endl;
}
return 0;
}
总结完毕啦~~