题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544
Problem 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条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
Floyd算法:
复杂度为(n3)
#include<cstdio>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100 + 5;
int g[maxn][maxn], N, M;
int main(void) {
while (~scanf("%d %d", &N, &M) && N) {
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++) {
if (i != j) g[i][j] = inf;
else g[i][j] = 0;
}
for (int i = 0; i < M; i++) {
int A, B, C;
scanf("%d %d %d", &A, &B, &C);
g[A][B] = C; g[B][A] = C;
}
for (int k = 1; k <= N; k++)
for (int i = 1; i <= N; i++)
if (k != i)
for (int j = 1; j <= N; j++)
if (i != j && g[i][k] + g[k][j] < g[i][j])
g[i][j] = g[i][k] + g[k][j];
printf("%d\n", g[1][N]);
}
return 0;
}
Bellman-Ford算法:
#include<cstdio>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m, w[maxn][maxn];
void bellman() {
int s = 1, d[maxn];
for (int i = 1; i <= n; i++)
d[i] = inf;
d[s] = 0;
for (int k = 1; k <= n; k++)//一轮操作最少得到1个点的最短距离
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)//通过相邻点的距离不断更新最短距离
if (d[j] > d[i] + w[i][j])
d[j] = d[i] + w[i][j];
printf("%d\n", d[n]);
}
int main(void) {
while (~scanf("%d %d", &n, &m) && n) {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i != j)w[i][j] = inf;
else w[i][j] = 0;
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
w[a][b] = w[b][a] = c;
}
bellman();
}
return 0;
}
上述编码没有发挥Bellman-Ford的优势,其复杂度为O(n3)
下述代码则为O(nm)
#include<cstdio>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m, cnt;
struct edge {
int u, v, w;
}e[10005];
void bellman() {
int s = 1, d[maxn];
for (int i = 1; i <= n; i++)
d[i] = inf;
d[s] = 0;//这里还可以修改一下判断可以更快
for (int k = 1; k <= n; k++)//一轮操作最少得到1个点的最短距离
for (int i = 0; i < cnt; i++) {
int x = e[i].u, y = e[i].v;
if (d[x] > d[y] + e[i].w)
d[x] = d[y] + e[i].w;
}
printf("%d\n", d[n]);
}
int main(void) {
while (~scanf("%d %d", &n, &m) && n) {
cnt = 0;
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
e[cnt].u = a; e[cnt].v = b; e[cnt].w = c; cnt++;
e[cnt].u = b; e[cnt].v = a; e[cnt].w = c; cnt++;
}
bellman();
}
return 0;
}
SFPA算法:
Bellman-Ford的优化版
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m;
struct edge {
int from, to, w;
edge(int a, int b, int c) :from(a), to(b), w(c) {}
};
vector<edge>e[maxn];
void spfa(int s) {//相当于对Bellman-Ford的优化,使用队列减少了很多无效操作
int dis[maxn];
bool inq[maxn];
for (int i = 1; i <= n; i++) {
dis[i] = inf; inq[i] = false;
}
dis[s] = 0;
queue<int>Q;
Q.push(s);
inq[s] = true;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = false;
for (int i = 0; i < e[u].size(); i++) {
int v = e[u][i].to, w = e[u][i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!inq[v]) {
inq[v] = true;
Q.push(v);
}
}
}
}
printf("%d\n", dis[n]);
}
int main(void) {
while (~scanf("%d %d", &n, &m) && n) {
for (int i = 1; i <= n; i++)e[i].clear();
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
e[a].push_back(edge(a, b, c));
e[b].push_back(edge(b, a, c));
}
spfa(1);
}
return 0;
}
链式向前星!
相关知识:https://blog.csdn.net/flymoyu/article/details/90319846
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1000005;
int n, m, cnt, head[maxn];
struct edge {
int to, w, nxt;
}e[maxn];
void init() {
for (int i = 0; i < maxn; i++) {
e[i].nxt = -1;
head[i] = -1;
}
cnt = 0;
}
void addedge(int u, int v, int w) {//向前星
e[cnt].to = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
void spfa(int s) {
int dis[maxn];
bool inq[maxn];
for (int i = 1; i <= n; i++) {
dis[i] = inf; inq[i] = false;
}
dis[s] = 0;
queue<int>Q;
Q.push(s);
inq[s] = true;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = false;
for (int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if (dis[v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w;
if (!inq[v]) {
inq[v] = true;
Q.push(v);
}
}
}
}
printf("%d\n", dis[n]);
}
int main(void) {
while (~scanf("%d %d", &n, &m) && n) {
init();
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
addedge(a, b, c);
addedge(b, a, c);
}
spfa(1);
}
return 0;
}
SFPA算法的效率和图的权有关,是不稳定的
下面是Dijkstra算法(稳定)
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m;
struct edge {
int from, to, w;
edge(int a, int b, int c) :from(a), to(b), w(c) {}
};
vector<edge>e[maxn];
struct node{
int id, dis;
node(int b, int c) {
id = b; dis = c;
}
bool operator <(const node& a)const {
return dis > a.dis;
}
};
void dijkstra() {
int s = 1;
int dis[maxn];
bool done[maxn];
for (int i = 1; i <= n; i++) {
dis[i] = inf; done[i] = false;
}
dis[s] = 0;
priority_queue<node>pq;
pq.push(node(s, dis[s]));
while (!pq.empty()) {
node u = pq.top(); pq.pop();//用距离s最近的点u
if (done[u.id])continue;//已经找到最短了,跳过
done[u.id] = true;//当前就是最短的距离,相当于放入A集合
for (int i = 0; i < e[u.id].size(); i++) {
edge y = e[u.id][i];
if (done[y.to])continue;
if (dis[y.to] > u.dis + y.w) {//更新备选点
dis[y.to] = u.dis + y.w;
pq.push(node(y.to, dis[y.to]));
}
}
}
printf("%d\n", dis[n]);
}
int main(void) {
while (~scanf("%d %d", &n, &m) && n) {
for (int i = 1; i <= n; i++)e[i].clear();
while (m--) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
e[a].push_back(edge(a, b, c));
e[b].push_back(edge(b, a, c));
}
dijkstra();
}
return 0;
}