zoukankan      html  css  js  c++  java
  • 【算法】最短路径算法

    最短路径算法


    Floyed

    PS:能求带负边图,但不能带负权回路
    可以求出任意两点之间的最短路径
    主代码:

    for(k=1;k<=n;k++)
    for(i=1;i<=n;i++)  
    for(j=1;j<=n;j++)  
    if(i!=j&&j!=k&&i!=k)  
    dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
    

    dijstra

    PS:不支持负边
    求单源最短路径,即起点只有一个
    主代码:

    #include<iostream>
    #include<cstring>
    #define maxn 9999999
    using namespace std;
    int f[101][101];
    int n,m,x,y,s;
    int pre[101];//记录前驱 
    int to[101];//从起点到当前节点的距离 
    int v[101];//是否访问过 
    int main()
    {
    	cin>>n>>m;
    	memset(f,maxn,sizeof(f));
    	for(int i=1;i<=m;i++)
    	{
    		cin>>x>>y>>s;
    		f[x][y]=f[y][x]=s;
    	}
    	for(int i=2;i<=n;i++)
    	{
    		to[i]=f[1][i];//从第一个点到每个点的初始距离 
    		if(f[1][i]!=maxn)//如果被修改前驱就是第一个点 
    		pre[i]=1;
    	}
    	v[1]=1;
        for(int i=2;i<=n;i++)
    	{
    		int minn=maxn;
    		int k=0;
    		for(int j=2;j<=n;j++)
    		if(v[i]==0&&to[i]<minn)//如果没被标记过且小于最小值就替换 
    		{
    			minn=to[i];
    			k=j;
    		}
    		v[k]=1;//找到了当前最短路 
    		for(int j=1;j<=n;j++)
    		if(to[k]+f[k][j]<to[j])//从当前最短路找下一条最短路 
    		to[j]=to[k]+f[k][j];
    	}
    }
    

    SPFA

    用(循环)队列优化的Bellman-Ford
    PS:支持负边,但不支持负环回路(如果回路只走一次就行)

    team[]为队列
    exist[]为一个点是否在队列中
    dis[i]记录从起点到i的最短距离
    w[i][j]表示从i到j的长度
    pre[]前驱 
    
    do
    {
    	head++;
    	exist[u]=0;
    	for枚举所有链接的点 
    	if(dis[v]>dis[u]+w[u][v])
    	{
    		dis[v]=dis[u]+w[u][v];
    		pre[v]=u;
    		if(exist[v]==0)
    		{
    			exist[v]=1;
    			tail++;
    			team[tail]=v; 
    		}
    	} 
    }
    while(head<tail)
    

    一个例题加深理解
    例题:洛谷P3371单源最短路径模板
    https://www.luogu.org/problemnew/show/P3371
    此处运用SPFA+链式前向星

    #include<iostream>
    using namespace std;
    int exist[500010];
    int team[2000000];
    int dis[500010];
    int head[500010];
    int n,m,s;
    int x,y,z;
    int cnt;
    int t=0,w=1;
    struct edge
    {
        int next;
        int to;
        int w;
    }edge[2500010];
    void add(int u,int v,int w)
    {
        edge[++cnt].w=w;
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt;
    }
    int main()
    {
        cin>>n>>m>>s;
        for(int i=1;i<=n;i++)
        dis[i]=2147483647;
        for(int i=1;i<=m;i++)
        {
            cin>>x>>y>>z;
            add(x,y,z);
        }
        dis[s]=0;
        team[1]=s;
        while(t<w)
        {
            t++;
            int u=team[t];//u等于入队的点 
            exist[u]=0;
            for(int i=head[u];i!=0;i=edge[i].next)//i从每个点能到的最后一条遍循环到第一条边 
            {
                int v=edge[i].to;//v等于每条遍的后面那个点 
                if(dis[v]>dis[u]+edge[i].w)//如果到这条遍后面的点距离比到这条边前面点加上边的权值小 
                {
                    dis[v]=dis[u]+edge[i].w;
                    if(!exist[v])
                    {
                        w++;
                        exist[v]=1;
                        team[w]=v;
                    }
                }
            }
        }
        for(int i=1;i<=n;i++) 
        cout<<dis[i]<<" ";
    }
    
  • 相关阅读:
    UIButton和UIImageView的区别
    大道至简第八章读后感
    简单登录界面
    大道至简第七章读后感
    计算成绩代码
    大道至简第六章读后感
    产生随机数代码
    大道至简第五章读后感
    计算成绩算法
    加密算法
  • 原文地址:https://www.cnblogs.com/BrokenString/p/9279536.html
Copyright © 2011-2022 走看看