全源最短路模板

全源最短路模板

题目

Johnson:

时间复杂度:\(O(nm+n(n+m)\log n)\)

#include<bits/stdc++.h>
using namespace std;
using pii=pair<long long,int>;
const int N=5005,INF=1e9;
int n,m,hd[N],ver[2*N],nxt[2*N],tot,cnt[N];//cnt:SPFA中记录路径边数,用于判负环
long long h[N],dis[N],w[2*N];//h势能,w用long long防止重赋权溢出)
bool vis[N];
void add(int u,int v,int c){
	ver[++tot]=v;w[tot]=c;nxt[tot]=hd[u];hd[u]=tot;
}
bool SPFA(int s){//SPFA求超级源点0到各点的最短路(势能),同时检测负环
	queue<int> q;
	memset(vis,0,sizeof(vis));
	memset(h,0x7f,sizeof(h));//初始化为极大值
	h[s]=0;
	q.push(s);
	while(q.size()){
		int u=q.front();q.pop();
		vis[u]=false;
		for(int i=hd[u];i;i=nxt[i]){
			int v=ver[i];
			if(h[v]>h[u]+w[i]){
				h[v]=h[u]+w[i];
				cnt[v]=cnt[u]+1;//更新路径边数
				if(cnt[v]>=n+1) return false;//包含超级源点共n+1个点,若边数≥n+1则有负环
				if(!vis[v]){
					q.push(v);
					vis[v]=true;
				}
			}
		}
	}
	return true;
}
void dij(int s){//Dij求调整后图的最短路
	for(int i=1;i<=n;i++) dis[i]=INF;
	priority_queue<pii,vector<pii>,greater<pii> > q;
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	q.push({0,s});
	while(q.size()){
		int u=q.top().second;q.pop();
		if(vis[u]) continue;
		vis[u]=true;
		for(int i=hd[u];i;i=nxt[i]){
			int v=ver[i];
			if(dis[v]>dis[u]+w[i]){
				dis[v]=dis[u]+w[i];
				q.push({dis[v],v});
			}
		}
	}
	return;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>n>>m;
	for(int i=1,u,v,w;i<=m;i++){
		cin>>u>>v>>w;
		add(u,v,w);
	}
	for(int i=1;i<=n;i++) add(0,i,0);//添加超级源点0,向所有点连权值为0的边
	if(!SPFA(0)){//第一步:SPFA求势能并判负环
		cout<<-1;
		return 0;
	}
	for(int u=1;u<=n;u++){//第二步:重赋权,使所有边权非负
		for(int i=hd[u];i;i=nxt[i]){
			w[i]+=h[u]-h[ver[i]];
		}
	}
	for(int i=1;i<=n;i++){//第三步:对每个点跑Dij,求出调整后的最短路,再还原真实距离
		dij(i);
		long long ans=0;
		for(int j=1;j<=n;j++){
			if(dis[j]==INF) ans+=1ll*j*INF;//不可达,则按题目要求用1e9代替
			else ans+=j*(dis[j]+h[j]-h[i]);//(dis[j]+h[j]-h[i]):计算出真实的最短路;并按照题目要求乘j
		}
		cout<<ans<<'\n';
	}
	return 0;
}

题目

Floyd:

时间复杂度:\(O(n^{3})\)

#include<bits/stdc++.h>
using namespace std;
int n,m,a[110][110];
int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){//初始化距离矩阵
		for(int j=1;j<=n;j++){
			if(i==j) continue;//自己到自己距离为0
			a[i][j]=INT_MAX;//不可达设为无穷大
		}
	}
	for(int i=1,u,v,w;i<=m;i++){//读入边,处理重边:取最小权值
		cin>>u>>v>>w;
		a[u][v]=min(a[u][v],w);
		a[v][u]=min(a[v][u],w);
	}
	//Floyd核心三重循环
	for(int k=1;k<=n;k++){//枚举中转点
		for(int x=1;x<=n;x++){//起点
			for(int y=1;y<=n;y++){//终点
				if(a[x][k]==INT_MAX||a[k][y]==INT_MAX) continue;//避免INT_MAX相加溢出,跳过不可达的中转
				a[x][y]=min(a[x][y],a[x][k]+a[k][y]);
			}  
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<a[i][j]<<' ';
		}
		cout<<'\n';
	}
	return 0;
}
posted @ 2026-08-15 14:22  decentz  阅读(2)  评论(0)    收藏  举报