您的位置:首页 > 编程语言

HDU 2544-最短路(Dijkstra算法 Floyd算法 SPFA算法,3种实现代码,包含路径)

2017-07-20 09:52 435 查看



题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544


最短路

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 67093    Accepted Submission(s): 29309


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

 

Sample Output

3
2
//3种最短路算法, 直接套模板
//由于数据比较水,所以Floyd算法也能过
#include <stdio.h>
#include <queue>
#include <stack>
#include <string.h>
#include <algorithm>
#define maxn 1005
#define inf 0x3f3f3f3f
using namespace std;

int dist[maxn];       //记录源点到各个点的最短路径长度
int edge[maxn][maxn];//邻接矩阵存边
int pre[maxn];      //记录一个路径中,到达某个点的前一个点
bool vis[maxn];     //记录某个元素是否在队列内
int cnt[maxn];    //记录一个元素入队的次数,如果大于nodenum-1,那么就存在负权回路
int Fdist[maxn][maxn]; //记录Floyd算法的任意两点的最短距离
int Fpre[maxn][maxn]; //记录一个路径中两点之间的中间点
queue<int>q;          //SPFA算法中用到的队列

void Floyd(int orig, int nodenum)
{
for(int i=1; i<=nodenum; i++)
for(int j=1; j<=nodenum; j++)
{
Fdist[i][j] = edge[i][j];
Fpre[i][j] = -1;
}

for(int k=1; k<=nodenum; k++)
for(int i=1; i<=nodenum; i++)
{
if(Fdist[i][k]!=inf)
{
for(int j=1; j<=nodenum; j++)
{
if(Fdist[i][j] > Fdist[i][k]+Fdist[k][j])
{
Fdist[i][j] = Fdist[i][k]+Fdist[k][j];
Fpre[i][j] = k;
}
}
}
}
}

void Dijkstra(int orig, int nodenum)
{
memset(vis, 0, sizeof(vis));
memset(pre, -1, sizeof(pre));
for(int i=1; i<=nodenum; i++)
{
dist[i] = edge[orig][i];
if(dist[i]!=inf)
pre[i] = orig;
}
vis[orig] = 1;
for(int i=1; i<nodenum; i++)
{
int u = orig, cntmin = inf;
for(int j=1; j<=nodenum; j++)
{
if(!vis[j]&&dist[j]<cntmin)
{
u = j;
cntmin = dist[j];
}
}
vis[u] = 1;
for(int j=1; j<=nodenum; j++)
{
if(!vis[j] && dist[j] > dist[u]+edge[u][j])
{
dist[j] = dist[u]+edge[u][j];
pre[j] = u;
}
}
}
}

bool SPFA(int orig, int nodenum)
{
while(!q.empty())
q.pop();
memset(vis, false, sizeof(vis));
memset(pre, -1, sizeof(pre));
memset(cnt, 0, sizeof(cnt));
for(int i=1; i<=nodenum; i++)
dist[i] = inf;
vis[orig] = true;
pre[orig] = orig;
cnt[orig]++;
dist[orig] = 0;

q.push(orig);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for(int v=1; v<=nodenum; v++)
{
if(dist[v] > dist[u]+edge[u][v])
{
dist[v] = dist[u]+edge[u][v];
pre[v] = u;
if(!vis[v])
{
vis[v] = true;
cnt[v]++;
q.push(v);
if(cnt[v]>nodenum-1)
return false;
}
}
}
}
return true;
}

//Floyd算法,点s到t的路径
void Floyd_path(int s, int t)
{
if(Fdist[s][t]==inf)
{
printf("%d---%d--no load\n", s, t);
return;
}
if(Fpre[s][t]==-1)
return;
int k = Fpre[s][t];
Floyd_path(s, k);
printf("%d->", k);
Floyd_path(k, t);
}

//Dijkstra和SPFA算法,最短路的路径
void p_path(int orig, int node)
{
stack<int>path;
while(node!=pre[node])
{
path.push(node);
node = pre[node];
}
printf("%d->", node);
while(!path.empty())
{
printf("%d->", path.top());
path.pop();
}
printf("\n\n");
}

void DisPath(int orig, int nodenum)
{
for(int i=1; i<=nodenum; i++)
{
if(dist[i]!=inf)
{
printf("%d到%d的最短路径长度是:%d\n", orig, i, dist[i]);
printf("路径是:");
p_path(orig, i);
}
else
{
printf("%d到%d没有路径\n\n", orig, i);
}
}
}

int main()
{
int nodenum, edgenum, orig;  //结点数,边数,源点
while(scanf("%d%d", &nodenum, &edgenum), nodenum+edgenum)
{
orig = 1;

for(int i=0; i<=nodenum; i++)
for(int j=1; j<=nodenum; j++)
edge[i][j] = i==j?0:inf;

for(int i=1; i<=edgenum; i++)
{
int u, v, cost;
scanf("%d%d%d", &u, &v, &cost);
edge[v][u] = edge[u][v] = min(edge[u][v], cost);
}
//SPFA(orig, nodenum);
Dijkstra(orig, nodenum);
//Floyd(orig, nodenum);
//printf("%d\n", Fdist[1][nodenum]);
printf("%d\n", dist[nodenum]);
}
return 0;
}


还有Bellman算法,但是提交后,一直runtime error,下面是代码(该代码未ac)
//Bellman算法
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#include <map>
#define maxn 1005
#define inf 0x3f3f3f3f
using namespace std;

map<int, int>mp;
struct Edge
{
int u, v;
}edge[maxn<<1];

int dist[maxn];
int pre[maxn];

void p_path(int orig, int node)
{
stack<int>path;
while(node!=pre[node])
{
path.push(node);
node = pre[node];
}
printf("%d->", node);
while(!path.empty())
{
printf("%d->", path.top());
path.pop();
}
printf("\n\n");
}

void DisPath(int orig, int nodenum)
{
for(int i=1; i<=nodenum; i++)
{
if(dist[i]!=inf)
{
printf("%d到%d的最短路径长度是:%d\n", orig, i, dist[i]);
printf("路径是:");
p_path(orig, i);
}
else
{
printf("%d到%d没有路径\n\n", orig, i);
}
}
}

bool Bellman(int orig,int nodenum, int edgenum)
{
for(int i=1; i<=nodenum; i++)
{
dist[i] = inf;
pre[i] = -1;
}
dist[orig] = 0;
pre[orig] = orig;
for(int i=1; i<nodenum; i++)
{
for(int j=0; j<edgenum; j++)
{
if(dist[edge[j].v] > dist[edge[j].u] + mp[edge[j].u*maxn + edge[j].v])
{
pre[edge[j].v] = edge[j].u;
dist[edge[j].v] = dist[edge[j].u] + mp[edge[j].u*maxn + edge[j].v];
}
}
}
bool res = true;
for(int j=0; j<edgenum; j++)
{
if(dist[edge[j].v] > dist[edge[j].u] + mp[edge[j].u*maxn + edge[j].v])
{
res = false;
break;
}
}
return res;
}
int main()
{
int u[maxn], v[maxn], cost[maxn];
int nodenum, edgenum, orig;
while(scanf("%d%d", &nodenum, &edgenum), nodenum+edgenum)
{
orig = 1;
int e = 0;
mp.clear();

for(int i=1; i<=edgenum; i++)
{
scanf("%d%d%d", &u[i], &v[i], &cost[i]);
}

//因为图是无向图,且可重边,所以用map[u*maxn + v]表示点u与点v的边的权值
for(int i=1; i<=edgenum; i++)
{
if(mp[u[i]
b4de
*maxn+v[i]]>0)
{
mp[v[i]*maxn+u[i]] = mp[u[i]*maxn+v[i]] = min(mp[u[i]*maxn+v[i]], cost[i]);
}
else
{
edge[e++].u = u[i];
edge[e-1].v = v[i];
edge[e++].u = v[i];
edge[e-1].v = u[i];
mp[v[i]*maxn+u[i]] = mp[u[i]*maxn+v[i]] = cost[i];
}
}
if(Bellman(orig, nodenum, e))
{
printf("%d\n", dist[nodenum]);
// DisPath(orig, nodenum);
}
else
printf("存在负权回路\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: