#include<iostream>
using namespace std;
int main(){
int dis[10],bak[10],i,k,n,m,u[10],v[10],w[10],check,flag;//bak数组用来备份数组dis
int inf=99999999;//用inf(infinity的缩写)存储一个我们认为的无穷大值
cout<<"请输入顶点个数n和边的条数m:"<<endl;
cin>>n>>m;
cout<<"请依次输入m条边,每条边起点为u,终点为v,权重为w。即u->v(w):"<<endl;
for(i=1;i<=m;i++){
//读入每一条边
cin>>u[i]>>v[i]>>w[i];
}
//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
for(i=1;i<=n;i++){
dis[i]=inf;
}
dis[1]=0;
//Bellman-Ford算法核心语句
/*
第一轮在对所有的边进行松弛后,得到的是从1号顶点"只能经过一条边"到达其余各顶点的最短路径长度
第二轮在对所有的边进行松弛后,得到的是从1号顶点"只能经过两条边"到达其余各顶点的最短路径长度
第k轮在对所有的边进行松弛后,得到的是从1号顶点"只能经过k条边"到达其余各顶点的最短路径长度
第n-1轮在对所有的边进行松弛后,得到的是从1号顶点"只能经过n-1条边"到达其余各顶点的最短路径长度
结束;(因为在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1条边,最短路径中不能包含回路)
*/
for(k=1;k<=n-1;k++){//只需要n-1轮
//将dis数组备份至bak数组中
for(i=1;i<=n;i++){
bak[i]=dis[i];
}
//进行一轮松弛
for(i=1;i<=m;i++){
if(dis[v[i]]>dis[u[i]]+w[i]){
dis[v[i]]=dis[u[i]]+w[i];
}
}
//松弛完毕后检测dis数组是否有更新
check=0;
for(i=1;i<=n;i++){
if(bak[i]!=dis[i]){
check=1;
break;
}
}
//如果dis数组没有更新,提前退出循环结束算法
if(check==0){
break;
}
}
//检测负权回路
/*
如果在进行了上面的Bellman-Ford算法后(即进行n-1轮松弛之后)仍然存在dis[v[i]]>dis[u[i]]+w[i](即仍然可以继续松弛),
则说明此图必然含有负权回路;
//如果一个图没有负权回路,那么最短路径所包含的边虽多为n-1条,即进行n-1轮松弛后最短路不会再发生变化
//反正,如果在进行n-1轮松弛后最短路仍然发生变化,那么此图中必然含有负权回路
*/
flag=0;
for(i=1;i<=m;i++){
if(dis[v[i]]>dis[u[i]]+w[i]){
flag=1;
}
}
if(flag==1){
cout<<"此图中含有负权回路"<<endl;
}
else{
//输出最终的结果
cout<<endl<<"1号顶点到其余各个顶点的最短路径为: "<<endl;
for(i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
}
return 0;
}
6.3Bellman-Ford——解决负权边
最新推荐文章于 2022-10-03 00:17:59 发布