最短路总结

今天是我入队的第180天。不知道以后的路还有多长,但还是要坚持下去!

一直学习别人的东西,看别人的总结,这次我也想自己写一份总结,也算不辜负我这半年的付出。

最早接触的算法应该就是最短路了,整整半年了,现在终于有资本说自己还是懂那么一种算法的。

之前学的时候总想把dijkstra,bellman ford,spfa,floyd全都总结出来,但网上的资料很零散,所以就把这次的总结当做我对acm的一点贡献吧~(大神勿喷,我还只能算是一个算法入门者)

以下总结基本都以hdu2544为例

1.dijkstra 邻接矩阵形式

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
using namespace std;

const int INF= 1<<30;
const int MAX=1050;

int dis[MAX],n,m;
int edges[MAX][MAX];
int visit[MAX];

//最小下标为1
void dijkstra(int v)
{
	int i,j;
	int u;
	memset(visit,0,sizeof(visit));//标记是否已求出最短路径
	fill(dis+1,dis+n+1,INF);
	dis[v]=0;

	while(1)		//最多循环n次就够了,每次找到 v到某一个点的最短路
	{						
		u=-1;
		for(j=1;j<=n;j++)	//找当前最短
			if((!visit[j])&&(u==-1||dis[j]<dis[u]))	
				u=j;
		if(u==-1)
			break;
		visit[u]=1;
		for(j=1;j<=n;j++)			//更新当前所有的最短路径
			if((!visit[j])&&(edges[u][j]<INF)&&(dis[u]+edges[u][j])<dis[j])
				dis[j]=dis[u]+edges[u][j];
	}

}

int main()
{
	int i,j,a,b,c;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)
			return 0;

		for(i=0;i<MAX;i++)	//矩阵初始化为INF
		{
			edges[i][i]=0;
			for(j=i+1;j<MAX;j++)
			{
				edges[i][j]=INF;
				edges[j][i]=INF;
			}
		}

		for(i=0;i<m;i++)		//获得各边之间的长度
		{
			scanf("%d%d%d",&a,&b,&c);
			if(edges[a][b]>c)
			{
				edges[a][b]=c;
				edges[b][a]=c;
			}
		}
		dijkstra(1);		//求以1为起点到各点的最短路径
		printf("%d\n",dis[n]);
	}
	return 0;
}
2.dijkstra邻接表形式

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

typedef long long LL;
const double pi=4.0*atan(1.0);
const int MAX=105;
const int INF=1<<29;
struct Edge{
	int v,val;
	Edge(){}
	Edge(int _v,int _val):v(_v),val(_val){}
};
vector<Edge> g[MAX];
int n;
int dis[MAX],vis[MAX];

void dijkstra(int s)
{
	memset(vis,0,sizeof(vis));
	fill(dis+1,dis+n+1,INF);
	dis[s]=0;

	while(1)
	{
		int u=-1;
		for(int v=1;v<=n;v++)
			if(!vis[v]&&(u==-1||dis[u]>dis[v]))
				u=v;
		if(u==-1)
			break;
		vis[u]=1;
		for(int i=0;i<g[u].size();i++)
		{
			int v=g[u][i].v;
			if(!vis[v]&&dis[v]>dis[u]+g[u][i].val)
				dis[v]=dis[u]+g[u][i].val;
		}
	}
}
int main()
{
	int i,j,k;
	int m;
	int x,y,z;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)
			return 0;
		for(i=1;i<=n;i++)
			g[i].clear();

		for(i=0;i<m;i++)
		{
			scanf("%d%d%d",&x,&y,&z);
			g[x].push_back(Edge(y,z));
			g[y].push_back(Edge(x,z));
		}
		dijkstra(1);
		printf("%d\n",dis[n]);
	}
	return 0;
}
3.dijkstra向前星

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

typedef long long LL;
const double pi=4.0*atan(1.0);
const int MAXN=10005;
const int MAX=105;
const int INF=1<<29;
struct Edge{
	int v,val;
	int next;
};
Edge edge[MAXN<<1];
int n;
int head[MAX],total;
int dis[MAX],vis[MAX];
void init()
{
	memset(head,-1,sizeof(head));
	total=0;
}
void addedge(int x,int y,int z)
{
	edge[total].v=y;
	edge[total].val=z;
	edge[total].next=head[x];
	head[x]=total++;
}
void dijkstra(int s)
{
	memset(vis,0,sizeof(vis));
	fill(dis+1,dis+n+1,INF);
	dis[s]=0;

	while(1)
	{
		int u=-1;
		for(int v=1;v<=n;v++)
			if(!vis[v]&&(u==-1||dis[u]>dis[v]))
				u=v;
		if(u==-1)
			break;
		vis[u]=1;
		for(int i=head[u];i!=-1;i=edge[i].next)
		{
			int v=edge[i].v;
			if(!vis[v]&&dis[v]>dis[u]+edge[i].val)
				dis[v]=dis[u]+edge[i].val;
		}
	}
}
int main()
{
	int i,j,k;
	int m;
	int x,y,z;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)
			return 0;
		init();
		for(i=0;i<m;i++)
		{
			scanf("%d%d%d",&x,&y,&z);
			addedge(x,y,z);
			addedge(y,x,z);
		}
		dijkstra(1);
		printf("%d\n",dis[n]);
	}
	return 0;
}
4.dijkstra优先队列优化+邻接表形式

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=100005;
const int INF=9999999;

int flag[MAXN];
int dist[MAXN],n;


struct Node{
	int id,val;
	Node(){}
	Node(int _id,int _val):id(_id),val(_val){}
	bool operator<(const Node &a)const
	{                //重载<,使优先队列队首始终是val最小的元素
		return val > a.val;
	}
};

struct Edge{
	int v,cost;                                         
	Edge(){}
	Edge(int _v,int _cost):v(_v),cost(_cost){}
};


vector<Edge>mp[MAXN]; //mp[i][j].v表示i的第j条边连接的是顶点v,权值为mp[i][j].cost


void dijkstra(int s)
{
	int i,j,k,v,cost;
	Node tep;

	memset(flag,0,sizeof(flag));
	for(i=0;i<10005;i++)
		dist[i]=INF;

	priority_queue<Node> que;
	dist[s] = 0;
	que.push(Node(s,0));                       //起点入队

	while(!que.empty())
	{
		tep = que.top();
		que.pop();
		if(flag[tep.id])
			continue;       //如果tep.id已经在集合中,不用拿出
		flag[tep.id] = 1;	//将tep.id放入集合
		for(i = 0;i < mp[tep.id].size(); i++)
		{
			v = mp[tep.id][i].v;
			cost = mp[tep.id][i].cost;
			if(!flag[v] && dist[v] > dist[tep.id] + cost)
			{                //松弛
				dist[v] = dist[tep.id] + cost;
				que.push(Node(v,dist[v]));              //加入集合
			}
		}
	}

}
int main()
{
	int i,j,k,m,T;
	int u,v,w;

	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)
			return 0;
		for(i = 1;i <= n; i++)
			mp[i].clear();
		for(i = 1;i <= m;i++)
		{
			scanf("%d%d%d",&u,&v,&w);
			mp[v].push_back(Edge(u,w));   //双向边
			mp[u].push_back(Edge(v,w));
		}
		dijkstra(1);
		printf("%d\n",dist[n]);
	}          

	return 0;
}

5.dijkstra优先队列优化+邻接矩阵

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAX=105;
const int INF=9999999;

struct Node{
	int id,val;
	Node(){}
	Node(int _id,int _val):id(_id),val(_val){}
	bool operator<(const Node &a)const
	{                //重载<,使优先队列队首始终是val最小的元素
		return val > a.val;
	}
};
int flag[MAX];
int dist[MAX],n,m;
int edges[MAX][MAX];

void dijkstra(int s)
{
	int i,j,k,v,cost;
	Node tep;
	memset(flag,0,sizeof(flag));
	for(i=0;i<MAX;i++)
		dist[i]=INF;

	priority_queue<Node> que;
	dist[s] = 0;
	que.push(Node(s,0));                                                               //起点入队

	while(!que.empty())
	{
		tep = que.top();
		que.pop();
		if(flag[tep.id])
			continue;		//如果tep.id已经在集合中,不用拿出
		flag[tep.id] = 1;	//将tep.id放入集合
		for(i = 1;i <= n; i++)
		{
			v = i;
			cost = edges[tep.id][i];
			if(!flag[v] &&cost<INF&& dist[v] > dist[tep.id] + cost)
			{                //松弛
				dist[v] = dist[tep.id] + cost;
				que.push(Node(v,dist[v]));                                     //加入集合
			}
		}
	}

}
int main()
{
	int i,j,a,b,c;

	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)
			return 0;

		for(i=0;i<MAX;i++)	//矩阵初始化为INF
		{
			for(j=0;j<MAX;j++)
			{
				if(i==j)
					edges[i][j]=0;
				else
					edges[i][j]=INF;

			}
		}

		for(i=0;i<m;i++)		//获得各边之间的长度
		{
			scanf("%d%d%d",&a,&b,&c);
			if(edges[a][b]>c)
			{
				edges[a][b]=c;
				edges[b][a]=c;
			}
		}

		dijkstra(1);		//求以1为起点到各点的最短路径
		printf("%d\n",dist[n]);
	}
	return 0;
}

6.bellman ford
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;

const int INF= 99999999;  
const int MAX= 1010;  


typedef struct Edge //边  
{  
	int u;
	int v;  
	int cost;  
}Edge;  

Edge edge[100000];  
int dis[MAX], pre[MAX];  

//最小下标为1
//点,     边,         起点
bool Bellman_Ford(int nodenum,int edgenum,int original)  //有向图的最短路
{  
	for(int i = 1; i <= nodenum; ++i) //初始化  
		dis[i] = INF;  
	dis[original]=0;

	for(int i = 0; i < nodenum - 1; i++)  //总循环 点数-1 次
		for(int j = 1; j <= edgenum; j++)	//每条边松弛
			if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)  
			{  
				dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;  
				pre[edge[j].v] = edge[j].u;  
			}  

	bool flag = 1; //判断是否含有负权回路  
	for(int i = 1; i <= edgenum; ++i)  
		if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)  
		{  
			flag = 0;  
			break;
		}  
		return flag;  
}  

void print_path(int root) //打印最短路的路径(反向)  
{  
	while(root != pre[root]) //前驱  
	{  
		printf("%d-->", root);  
		root = pre[root];  
	}  
	if(root == pre[root])  
		printf("%d\n", root);  
}  

int main()  
{  
	int i,j;
	int N,M;
	int a,b,c;
	while(scanf("%d%d",&N,&M)!=EOF)
	{
		if(N==0&&M==0)
			return 0;
		for(i=0;i<100000;i++)
		{
			edge[i].cost=INF;
			edge[i].u=edge[i].v=0;
		}

		j=1;
		for(i=0;i<M;i++)
		{
			scanf("%d%d%d",&a,&b,&c);

			edge[j].u=a;
			edge[j].v=b;
			edge[j++].cost=c;

			edge[j].u=b;
			edge[j].v=a;
			edge[j++].cost=c;

		} 
		Bellman_Ford(N,M*2,1);

		printf("%d\n",dis[N]);

	}
	return 0;  
}  
7.spfa链表

注意这个模板求的是最长路,相信你自己可以改成最短路的

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include<map>
#include<stack>
#include<vector>
using namespace std;


const int MAX= 110;  
int n,m;

struct Edge{
	int v,cost;                                         
	Edge(){}
	Edge(int _v,int _cost):v(_v),cost(_cost){}
};

vector<Edge> edge[110];  
int dis[MAX], pre[MAX];  
int v[MAX];
int visit[MAX];

void spfa(int s)
{
	queue<int> k;
	int i,h;
	for(i=1;i<=n+1;i++)
	{
		dis[i]=-5000;
		visit[i]=0;
	}

	k.push(s);
	dis[s]=0;
	visit[s]=1;

	while(!k.empty())
	{
		h=k.front();
		k.pop();
		visit[h]=0;
		for(i=0;i<edge[h].size();i++)
		{
			if(dis[h]+edge[h][i].cost>dis[edge[h][i].v])
			{
				dis[edge[h][i].v]=dis[h]+edge[h][i].cost;
				pre[edge[h][i].v]=h; 
				if(!visit[edge[h][i].v])
				{
					k.push(edge[h][i].v);
					visit[edge[h][i].v]=1;
				}
			}
		}
	}
}

void print_path(int root) //打印最短路的路径(反向)  
{  
	stack<int> st;

	while(!st.empty())
		st.pop();
	while(root != pre[root]) //前驱  
	{  
		st.push(root);  
		root = pre[root];  
	}  
	if(root == pre[root])  
		st.push(root);
	printf("circuit : ");
	while(!st.empty())
	{
		if(st.top()==n+1)
		{
			printf("1\n");
			break;
		}
		else
			printf("%d->",st.top());
		st.pop();
	}
}  

int main()  
{  
	int i,j,k;
	int a,b,c;
	int T;
	int cas=1;

	while(scanf("%d",&T)!=EOF)
	{
		cas=1;
		while(cas<=T)
		{
			if(cas!=1)
				printf("\n");

			scanf("%d",&n);
			for(i=1;i<=n+1;i++)
				edge[i].clear();
			for(i=1;i<=n;i++)
				scanf("%d",v+i);
			v[n+1]=0;
			for(i=0;i<=n+1;i++)
				pre[i]=i;
			scanf("%d",&m);

			for(i=1;i<=m;i++)
			{
				scanf("%d%d",&a,&b);   
				edge[a].push_back(Edge(b,v[b]));

			}

			spfa(1);
			printf("CASE %d#\n",cas++);

			printf("points : %d\n",dis[n+1]);
			print_path(n+1);
		}
	}
	return 0;  
}  

8.spfa邻接矩阵

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;

const int INF= 99999999;  
const int MAX= 1010;  

int n,m,edges[MAX][MAX];
int visit[MAX];
int dis[MAX];
void spfa(int s)
{
	queue<int> k;
	int i,h;

	for(i=1;i<=n;i++)
	{
		dis[i]=INF;
		visit[i]=0;
	}

	k.push(s);
	dis[s]=0;
	visit[s]=1;

	while(!k.empty())
	{
		h=k.front();
		k.pop();
		visit[h]=0;
		for(i=1;i<=n;i++)
		{
			if(edges[h][i]<INF&&dis[h]+edges[h][i]<dis[i])
			{
				dis[i]=dis[h]+edges[h][i];
				if(!visit[i])
				{
					k.push(i);
					visit[i]=1;
				}
			}
		}
	}
}
int main()
{
	int i,j;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)
			return 0;

		for(i=0;i<=n;i++)	//矩阵初始化为INF
		{
			for(j=0;j<=n;j++)
			{
				if(i==j)
					edges[i][j]=0;
				else
					edges[i][j]=INF;
			}
		}
		int a,b,c;
		for(i=0;i<m;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			if(edges[a][b]>c)
			{
				edges[a][b]=c;
				edges[b][a]=c;
			}
		}     
		spfa(1);
		printf("%d\n",dis[n]);
	}
	return 0;
}
9.floyd

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
using namespace std;

const int INF= 999999999;
const int N=1005;

int n,m;
int edges[N][N];

//最小下标为 1
void floyd()    //Floyd算法  
{  
	int i, j, k;  
	//最外层 节点个数次 循环
	for(k = 1; k <= n; k++)     //k为中间点  
		for(i = 1; i <= n; i++)  
			for(j = 1; j <= n; j++)  
				if(edges[i][k]!=INF&&edges[k][j]!=INF)
					if(edges[i][k] + edges[k][j] <  edges[i][j])  
						edges[i][j] = edges[i][k] + edges[k][j];  
}  

int main()
{
	int i,j,a,b,c;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)
			return 0;

		for(i=0;i<N;i++)	//矩阵初始化为INF
		{
			edges[i][i]=0;

			for(j=i+1;j<N;j++)
			{
				edges[i][j]=INF;
				edges[j][i]=INF;
			}
		}

		for(i=0;i<m;i++)		//获得各边之间的长度
		{
			scanf("%d%d%d",&a,&b,&c);
			if(edges[a][b]>c)
			{
				edges[a][b]=c;
				edges[b][a]=c;
			}
		}
		floyd();
		printf("%d\n",edges[1][n]);
	}
	return 0;
}
没什么注释,希望能对你们学最短路有帮助~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值