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


题目链接: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]*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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值