最短路的几种算法

单源无负权最短路:Dijkstra
多源无负权最短路:Floyd
单源负权最短路:Bellman-ford,SPFA
以hdu 2544为例
Dijkstra


#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> par;
const int maxv = 1e5+5;
const int inf = 1000000000;

struct Node{
    int v,dis;
    Node(){}
    Node(int v,int dis) : v(v),dis(dis){}
    bool operator <(const Node &a)const{
        return dis > a.dis;
    }

};
vector<Node> node[maxv];
int dis[maxv];
bool vis[maxv] = {false};
priority_queue<Node> q;
int n,m,u,v,w;
void Dijkstra(int s){
    fill(dis,dis+maxv,inf);
    fill(vis,vis+maxv,false);
    dis[s] = 0;
    q.push(Node(s,0));
    Node st;
    while(!q.empty()){   
        st = q.top();q.pop();
        if(vis[st.v]) continue;
		vis[st.v] = true;
        for(int j = 0; j < node[st.v].size(); j++){
            int v = node[st.v][j].v;
            if(!vis[v] && dis[v] > node[st.v][j].dis + dis[st.v]){
                dis[v] = node[st.v][j].dis + dis[st.v]; 
                q.push(Node(v,dis[v]));
            }
        }

    }
}

int main(){
    while(scanf("%d%d",&n,&m),n || m){
        for(int i = 0; i < maxv; i++){
            node[i].clear();
        }
        for(int i = 0; i < m; i++){
            scanf("%d%d%d",&u,&v,&w);
            node[u].push_back(Node(v,w));
            node[v].push_back(Node(u,w));
        }
        int st,ed;
        Dijkstra(1);
        printf("%d\n",dis[n]);
    }
}

Floyd

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10002;
const int inf = 0x3fffffff;
struct Node {
	int v, dis; // v表示邻接边的目的顶点,dis表示邻边的权
    Node(int v,int dis):v(v),dis(dis){}
};
int d[maxn][maxn];
int n,m,u,v,val;
void Floyd(){
	for(int k = 1; k <= n; k++){
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(d[i][j] != inf && d[k][j] != inf && d[i][k] + d[k][j] < d[i][j]){
					d[i][j] = d[i][k] + d[j][k];
				}
			}
		}
	}
}

int main(){
    scanf("%d%d",&n,&m);
	fill(d[0],d[0] + maxn*maxn,inf);
    for(int i = 0; i < m; i++){
        scanf("%d%d%d",&u,&v,&val);
        d[u][v] = d[v][u] = val;
    }
    Floyd();
    for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			printf("%d ",d[i][j]);
		}
		printf("\n");
	}
}
注意:hdu2544会内存超限

Bellman-ford:

 #include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
const int inf = 0x3fffffff;
struct Node{
    int v,dis;
    Node(int v,int dis):v(v),dis(dis){}
};
vector<Node> Adj[maxn];
int n,m,u,v,val;
int d[maxn+5];
bool bellman(int s){
    fill(d,d+maxn,inf);
    d[s] = 0;
    for(int i = 0; i < n - 1 ; i++){
        for(int u = 1; u <= n; u++){
            for(int j = 0; j < Adj[u].size(); j++){
                int v = Adj[u][j].v;
                int dis = Adj[u][j].dis;
                if(d[v] > dis + d[u]) d[v] = dis + d[u];
            }
        }
    }

    // 以下为判断负环的代码负环的意思是一个环的权值加起来为负值
    for(int u = 1; u <= n; u++){
        for(int j = 0; j < Adj[u].size(); j++){
            int v = Adj[u][j].v;
            int dis = Adj[u][j].dis;
            if(d[u] + dis < d[v]){//仍然可以松弛
                return false;
            }
        }
    }
    return true;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 0; i < maxn; i++) Adj[i].clear();
    for(int i = 0; i < m; i++){
        scanf("%d%d%d",&u,&v,&val);
        Adj[u].push_back(Node(v,val));
       Adj[v].push_back(Node(u,val));
    }
    bellman(1);
    printf("%d\n",d[n]);
}

SPFA:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
const int inf = 0x3fffffff;
struct Node {
	int v, dis; // v表示邻接边的目的顶点,dis表示邻边的权
    Node(int v,int dis):v(v),dis(dis){}
};
vector<Node> adj[maxn]; //adj为邻接表
int d[maxn],num[maxn];//起点到各个点的距离 num记录顶点的入队次数
bool inq[maxn]; //顶点是否在队列中
int n,m,u,v,val;
bool spfa(int s) {
	//初始化
	memset(inq, false, sizeof(inq));
	memset(num, 0, sizeof(num));
	fill(d, d + maxn, inf);

	//源点入队
	queue<int> q;
	q.push(s); 
	inq[s] = true;//源点已入队
	num[s]++;//源点入队数加1
	d[s] = 0;

	//主体
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		inq[u] = false;
		for (int j = 0; j < adj[u].size(); j++) {
			int v = adj[u][j].v;
			int dis = adj[u][j].dis;
			if (d[u] + dis < d[v]) {
				d[v] = d[u] + dis;
				if (!inq[v]) {
					q.push(v);
					inq[v] = true;
					num[v]++;
					if (num[v] >= n) return false; // 有负环
				}
			}
		}
	}
	return true;
}
int main(){
    while(scanf("%d%d",&n,&m),m || n){
    for(int i = 0; i < maxn; i++) adj[i].clear();
    for(int i = 0; i < m; i++){
        scanf("%d%d%d",&u,&v,&val);
        adj[u].push_back(Node(v,val));
       adj[v].push_back(Node(u,val));
    }
    spfa(1);
    printf("%d\n",d[n]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值