最短路算法


 
   
 
    
通过此篇博客介绍最短路的各种算法:

 
    
1.dijkstra    邻接矩阵。                      
 贪心操作(找最小值点)+ 松弛操作(更新值)                                                    时间复杂度O(N^2)
 
    
 
    
 
    
2.dijkstra    邻接表+优先级队列优化。 
记录每一个点出发的所有的边,并且采用优先级队列代替贪心操作+松弛操纵         时间复杂度O(M*lgN)

ps:dijkstra不能解决含有负权值的最短路问题,1适用于稠密图,2适用于稀疏图。

 
    
3.floyd       dp思想dis[i][j]=min(dis[i][j]+dis[i][k]+dis[k][j])
对于时间复杂度要求不高的两点间最短路求解 代码非常简单                                  时间复杂度O(N^3)
 
    
 
    
 
    
 
    
4.bellman-Ford 用于解决含有负权值得最小路问题                                                 时间复杂度O(M*N)                                       
 
    
 
    
 
    
下面以一道例题实际讲解:
 
    

最短路

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 56545    Accepted Submission(s): 24974

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
#include
#include
#include
#include
using namespace std;

int book[1001];
int n,m;
int map[1001][1001];
int f[1001];
vectorg[1001];
const int inf=0x3f3f3f3f;
int dis[1001];

struct node{
	int u,d;
	friend bool operator <(node n1,node n2)
	{
		return n1.dq;
	q.push(node{1,0});
	book[1]=1;
	while(!q.empty())
	{
		node tt=q.top();q.pop();
		
		int u=tt.u;
		
		for(int i=0;idis[u]+map[u][v]&&!book[v])
			{
				dis[v]=dis[u]+map[u][v];
				q.push(node{v,dis[v]});
			 } 
		}
	}
	/*
	for(int p=1;p<=n;p++)
	{
		int index,minn=inf;
		for(int i=1;i<=n;i++)
		{
			if(dis[i]dis[index]+map[index][g[index][i]])
			{
				dis[g[index][i]]=dis[index]+map[index][g[index][i]];
				f[g[index][i]]=index;
			}
		}
	 } 
	 */
}
int main()
{
	while(cin>>n>>m,m+n)
	{
		for(int i=0;i<=n;i++)g[i].clear();
		memset(map,0,sizeof(map));
		while(m--)
		{
			int x,y,z;cin>>x>>y>>z;
			g[x].push_back(y);g[y].push_back(x);
			map[x][y]=map[y][x]=z;
		}
		dijkstral();
		cout<



 
    
 
    
dijkstra 实现打印路径并且输出
 
    
伪码描述:
 
    
1.清楚所有点的标记。
2.d[s]=0,其他d[i]均设为inf
 
    
3.循环n次{
在所有未标记的点中,找到dis值最小的点pos
给pos标记
对于从pos出发的所有边(map[pos][i]),更新
dis[i]=min(dis[i],dis[pos]+map[pos][i];
(如果需要打印出路径,将上式改为:
if(dis[i]>dis[pos]+map[pos][i])
{dis[i]=dis[pos]+map[pos][i],f[i]=pos;}
//如果需要打印路径,这里换成if判断,并且记录下前驱结点
)
}
 
    
法一:使用邻接矩阵
 
    
 
    
[cpp] view plain copy
print ?
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5. using namespace std;  
  6.   
  7. const int inf=0x3f3f3f3f;  
  8. int map[101][101];  
  9. int dis[101];  
  10. int book[101];  
  11. int f[101];  
  12. int n,m;  
  13.   
  14. void dijkstra(int s,int e)  
  15. {  
  16.     memset(dis,0x3f,sizeof(dis));  
  17.     dis[s]=0;  
  18.       
  19.       
  20.     for(int i=1;i<=n;i++)  
  21.     {  
  22.         int minn=inf;  
  23.         int pos;  
  24.           
  25.         for(int j=1;j<=n;j++)  
  26.         {  
  27.             if(!book[j]&&dis[j]<=minn)  
  28.             {  
  29.                 minn=dis[j];  
  30.                 pos=j;  
  31.             }  
  32.         }  
  33.           
  34.         book[pos]=1;  
  35.         for(int k=1;k<=n;k++)  
  36.         {  
  37.             dis[k]=min(dis[k],dis[pos]+map[pos][k]);  
  38.             /* 
  39.             if(dis[k]>dis[pos]+map[pos][k]) 
  40.             { 
  41.                 dis[k]=dis[pos]+map[pos][k]; 
  42.                 f[k]=pos; 
  43.             } 
  44.             */  
  45.         }  
  46.     }     
  47. }  
  48. void printpath(int e)  
  49. {  
  50.     if(e==1)
  51. {
  52. cout<<1;
  53. return;
  54. }  
  55.       
  56.     if(e==1)  
  57.      
  58.       
  59. }  
  60. int main()  
  61. {  
  62.     while(cin>>n>>m,n+m)  
  63.     {  
  64.         memset(book,0,sizeof(book));  
  65.         for(int i=1;i<=n;i++)  
  66.         for(int j=1;j<=n;j++)  
  67.         {  
  68.             map[i][j]=(i==j ? 0 : inf);  
  69.         }  
  70.         int x,y,z;  
  71.           
  72.         while(m--)  
  73.         {  
  74.             cin>>x>>y>>z;  
  75.             map[x][y]=map[y][x]=z;  
  76.         }  
  77.         int s=1;f[s]=-1;  
  78.         int e=n;      
  79.           
  80.         dijkstra(s,e);  
  81.           
  82.         cout<
  83.         /* 
  84.         printpath(e); 
  85.         cout< 
  86.         */   
  87.     }  
  88.       
  89.     return 0;  
  90.  }   
法二:使用邻接表+打印输出
对于无权图的邻接表表示法是 
vectorgraph[101];
map[0].push_back(vlaue);

 //输出起点是0,并且与之相邻的所有的点 
for(int i=0;i	cout<	int from,to,dist;
	edge(int a,int b,int c):from(a),to(b),dist(c){}; 
}; 
 
 vectorgraph[maxn];graph[0]代表起点是0下标的边的序号
 
 vectoredges;//存储所有的边,并且给每一条边一个序号
 
 void addEdge(int from,int to,int dist) 
 {
 	edges.push_back(dege(from,to,dist));
 	graph[from].push_back(edges.size()-1);
 }
 
 
    
[cpp] view plain copy
print ?
  1. #include  
  2. #include  
  3. #include   
  4. #include  
  5. using namespace std;  
  6.   
  7. int n,m;  
  8. int f[101];  
  9. int dis[101];  
  10. int book[101];  
  11. const int inf=0x3f3f3f3f;  
  12. struct edge{  
  13.     int from,to,dist;  
  14.     edge(int a,int b,int c):from(a),to(b),dist(c){};  
  15. };  
  16.   
  17. vector edges;  
  18.   
  19. vector<int>graph[101];  
  20.   
  21.   
  22. void dijkstra()  
  23. {  
  24.     memset(dis,0x3f,sizeof(dis));  
  25.     dis[1]=0;  
  26.       
  27.     for(int k=1;k<=n;k++)  
  28.     {  
  29.         int pos,minn=inf;  
  30.           
  31.         for(int i=1;i<=n;i++)  
  32.         {  
  33.             if(!book[i]&&dis[i]<=minn)  
  34.             {  
  35.                 pos=i;  
  36.                 minn=dis[i];  
  37.             }  
  38.         }  
  39.         book[pos]=1;  
  40.           
  41.         for(int i=0;i
  42.         {  
  43.             dis[edges[graph[pos][i]].to]=min(dis[edges[graph[pos][i]].to],dis[pos]+edges[graph[pos][i]].dist);  
  44.             /* 
  45.             if(dis[edges[graph[pos][i]].to]>dis[pos]+edges[graph[pos][i]].dist)  
  46.             { 
  47.                 dis[edges[graph[pos][i]].to]=dis[pos]+edges[graph[pos][i]].dist; 
  48.                 f[edges[graph[pos][i]].to]=pos; 
  49.             } 
  50.             */  
  51.         }  
  52.     }  
  53. }  
  54.   
  55. void printPath(int s)  
  56. {  
  57. if(step==1) { cout<<1; return; } int ns=edges[f[step]].from; printpath(ns); cout<<"->"<
  58.   
  59. }  
  60. int main()  
  61. {  
  62.     while(cin>>n>>m,n+m)  
  63.     {  
  64.         memset(book,0,sizeof(book));  
  65.         edges.clear();  
  66.         for(int i=0;i<=n;i++)graph[i].clear();  
  67.           
  68.         while(m--)  
  69.         {  
  70.             int x,y,z;  
  71.             cin>>x>>y>>z;  
  72.               
  73.             edges.push_back(edge(x,y,z));  
  74.             graph[x].push_back(edges.size()-1);  
  75.               
  76.             edges.push_back(edge(y,x,z));  
  77.             graph[y].push_back(edges.size()-1);  
  78.         }  
  79.           
  80.       
  81.         dijkstra();  
  82.           
  83.     //  f[1]=-1;  
  84.     //  printPath(n);  
  85.     //  cout<  
  86.           
  87.         cout<
  88.     }  
  89.       
  90.     return 0;  
  91. }  
法三:邻接表+优先级队列+路径打印输出
#include
#include
#include
#include
using namespace std;

struct edge{
	int u,v,w;
};
vectoredges;

struct hnode{
	int d,u;
	friend bool operator <(hnode h1,hnode h2)
	{
		return h1.d>h2.d;
	}
};
vectorgraph[110];

int n,m;
int book[110];
int dis[110];
int f[110];
const int inf=0x3f3f3f3f;
void dijkstra()
{
	memset(book,0,sizeof(book));
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	
	priority_queueheap;
	heap.push(hnode{0,1});
	while(!heap.empty())
	{
		hnode h=heap.top();heap.pop();
		
		int u=h.u;
                if(book[u])continue;book[u]=1;
		for(int i=0;idis[u]+w&&!book[v])
			{
				dis[v]=dis[u]+w;
				heap.push(hnode{dis[v],v});
				f[v]=u;
			}
		}
		
	}
}
void insert(int x,int y,int z)
{
	edges.push_back(edge{x,y,z});
	graph[x].push_back(edges.size()-1);
}
void print(int i)
{
	if(i==1){cout<<1;return;
	}
	print(f[i]);
	cout<<"->"<>n>>m,n+m)
	{
		edges.clear();
		for(int i=0;i<=n;i++)graph[i].clear();
		while(m--)
		{
			int x,y,z;
			cin>>x>>y>>z;
			insert(x,y,z);
			insert(y,x,z);
		}
		
		dijkstra();
	//	print(n);
		cout<


 
  
 
  
 
  
 
  
  4:floyd算法 
  
#include
#include
#include
using namespace std;

const int inf = 0x3f3f3f3f;
int map[102][102];
int book[102];
int n, m;
int main()
{
	while (cin >> n >> m, n + m)
	{
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				map[i][j] = (i == j ? 0 : inf);

		for (int i = 0; i < m; i++)
		{

			int x, y, z;
			cin >> x >> y >> z;
			map[x][y] = map[y][x] = z;
		}

		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				for (int k = 1; k <= n; k++)
				{

					map[j][k] = min(map[j][k], map[j][i] + map[i][k]);
				}

		cout << map[1][n] << endl;
	}

	return 0;
}


 
  

你可能感兴趣的:(最短路,学习资料)