全源最短路模板
全源最短路模板
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;
}

浙公网安备 33010602011771号