Bellman Ford 算法 可以存在负权边的情况下解决单源最短路问题和,当出现负权回路时返回布尔值0,不然,则返回1,并可以源点到各点输出最短路径
主要步骤:
1、建立图(连接矩阵);
2、运行Bellman Ford 算法:
对各点初始化;
对图中的每一条边进行先后松弛n-1次
检测是否有回路:当出现d[v]>d[u]+w(u,v)时即存在负权回路
3、输出结果
#include<stdio.h>
#define MAX 1000000
#define maxsize 10001
int G[maxsize][maxsize];
typedef struct
{
char ch; //节点字符
int pre;//前驱
int d; //距离
}Node;
Node V[maxsize];
void input(int n,int e)//节点和边的录入 及建立连接矩阵图G
{
int i,j,find,weight,s,d;
char ch1,ch2;
printf("请输入图的顶点 第一个顶点默认为源点\n");
for(i=0;i<n;i++)
scanf("%c ",&V[i].ch);
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
G[i][j]=MAX;
for(i=1;i<=e;i++)
{
scanf("%c %c %d ",&ch1,&ch2,&weight);
find=0;
for(j=0;find<2&&j<n;j++)
if(ch1==V[j].ch)
{
s=j;
find++;
}
else if(ch2==V[j].ch)
{
d=j;
find++;
}
G[s][d]=weight;
}
}
void INTIALIZE_SINGLE_SOURCE(int n)//各节点最短距离和前驱的初始化
{
int i;
for(i=0;i<n;i++)
{
V[i].d=MAX;
V[i].pre=-1;
}
V[0].d=0;
}
void RELAX(int u,int v)//松弛
{
if(V[v].d>V[u].d+G[u][v])
{
V[v].d=V[u].d+G[u][v];
V[v].pre=u;
}
}
int BELLMAN_FORD(int n)//BELLman ford 算法
{
int u,v,k;
INTIALIZE_SINGLE_SOURCE(n);
for(k=1;k<n;k++) //对每条边都要松弛n-1次
for(u=0;u<n;u++)
for(v=0;v<n;v++)
if(G[u][v]<MAX)
RELAX(u,v);
for(u=0;u<n;u++)//判断图中是否有负权回路
for(v=0;v<n;v++)
if(V[v].d>V[u].d+G[u][v])
return 0; //有回路返回布尔值0
return 1;//没回路返回布尔值1
}
void printpath(int i)//路径输出
{
if(V[i].pre==-1)
{
printf("%c->",V[i].ch);
return ;
}
else
{
printpath(V[i].pre);
printf("-%c",V[i].ch);
}
}
void print(int n,int flag)//输出
{
int i;
if(flag==0)
printf("有回路\n");
else
{
for(i=0;i<n;i++)
if(V[i].pre!=-1)
{
printf("%d: ",V[i].d);
printpath(i);
printf("\n");
}
else if(i==0)
printf("%d %c\n",V[i].d,V[i].ch);
else
printf(" 无穷大 %c\n",V[i].ch);
}
}
int main()
{ freopen("1.txt","r",stdin);
int n,e,flag;
printf("请输入图的顶点的个数n和边数e:\n");
scanf("%d%d ",&n,&e);
input(n,e); //节点和边的录入 及建立连接矩阵图G
flag=BELLMAN_FORD(n); //BELLman ford 算法 有回路返回布尔值0,没回路返回布尔值1
print(n,flag);//输出
return 0;
}
测试数据
5 10
s t x y z
s t 6
s y 7
t y 8
t x 5
t z -4
y x -3
y z 9
z x 7
z s 2
x t -2