最短路三种算法(Floyd+dij(优先队列优化版)+spfa)

单源最短路

Floyd(纯暴力)

思想:贪心+暴力枚举;
看代码就能理解了

void Floyd()
{
	//初始化dis[][]为很大的值;
	//注意在输入时需要将dis[x][y],dis[y][x],都录入;
	for(int k=1;k<=n;++k)
	for(int i=1;i<=n;++i)
	for(int j=1;j<=n;++j){
		dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]); //单纯的暴力枚举每一个点;
	}
}

dij+优先队列优化

算法思想:
1.将与起点相连的点都遍历一次;
2·遍历的顺序为每次的最小边遍历(此处用优先队列优化,保证每一次队首都是最小边);
注意:以最小边的顺序遍历既保证了该点到其余点的路径尽量的小,逐渐更新距离;

模板题目链接
题意:即找到1点到n点的最短距离;

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e5+55;
int head[N],dis[123];
int cnt;
struct node{
    int to,val,next;
}mp[N];
struct nod{                                //优先队列元素,u表示节点,val表示u到起点的距离;
    int u,val;
    bool friend operator<(nod a, nod b)
    {
        return a.val>b.val;
    }
};
void add(int x, int y, int val)    //链式向前星建边;
{
    mp[cnt].to=y;
    mp[cnt].val=val;
    mp[cnt].next=head[x];
    head[x]=cnt++;
    mp[cnt].to=x;
    mp[cnt].val=val;
    mp[cnt].next=head[y];
    head[y]=cnt++;
}
void dij()            //核心代码;
{
    bool p[123];
    memset(dis,inf,sizeof(dis));           //初始化,dis[];
    memset(p,true,sizeof(p));              //p作为标记数组,记录节点是否已经被遍历;
    dis[1]=0;
    priority_queue<nod >q;
    q.push(nod{1,dis[1]});
    while(!q.empty()){
        nod are=q.top();
        q.pop();
        int to,val,u;
        u=are.u;
        if(!p[u]) continue;
        p[u]=false;
        for(int i=head[u];~i;i=mp[i].next){
            to=mp[i].to;
            val=mp[i].val;
            if(dis[to]>dis[u]+val){
                dis[to]=dis[u]+val;
                q.push(nod{to,dis[to]});
            }
        }
    }
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)&&(n+m)){
        int x,y,val;
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&x,&y,&val);
            add(x,y,val);
        }
        dij();
        printf("%d\n",dis[n]);
    }
    return 0;
}

Spfa(bfs暴力搜索)

从起点出发,求两点间的距离,将其压入队列,依次更新所有的边,找到min(dis)
注意:条件dis[to]>dis[u]+val;如果相同就不压入,保证了不重复,一个点可能多次被压入队列;
题目:还是上面的例题;
Spfa算法实际就是对每一条边的遍历,有一些题可能卡数据;

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e5+55;
int head[N],dis[123];
int cnt;
struct node{
    int to,val,next;
}mp[N];
void add(int x, int y, int val)
{
    mp[cnt].to=y;
    mp[cnt].val=val;
    mp[cnt].next=head[x];
    head[x]=cnt++;
    mp[cnt].to=x;
    mp[cnt].val=val;
    mp[cnt].next=head[y];
    head[y]=cnt++;
}
void Spfa()  //核心代码;
{
    bool p[123];
    memset(dis,inf,sizeof(dis));
    memset(p,false,sizeof(p));
    queue<int > q;
    dis[1]=0;
    p[1]=true;
    q.push(1);
    int to,val,u;
    while(!q.empty()){
        u=q.front();
        q.pop();
        p[u]=false;
        for(int i=head[u];~i;i=mp[i].next){
            to=mp[i].to;
            val=mp[i].val;
            if(dis[to]>dis[u]+val){
                dis[to]=dis[u]+val;
                if(!p[to]) {               //表示当u点没有再队列中时才压入队列,否则不压入;
                    q.push(to);
                    p[to]=true;
                }
            }

        }
    }
}
int main()
{
    int n,m,x,y,val;
    while(~scanf("%d%d",&n,&m)&&(n+m)){
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&x,&y,&val);
            add(x,y,val);
        }
        Spfa();
        printf("%d\n",dis[n]);
    }
    return 0;
}

你可能感兴趣的:(图论)