Bellman-Ford算法主要思想就是一个松弛
在有向图中,在寻找的过程中找到的是只能是当前的最小权重,但是当路径向后推移的时候,可能就会有更小的权重出现了,那就换一条路(变化parent)给他松弛一下,得到更小的路径。
最后那个布尔值是在检查是否存在一个可从源节点到达的权重为负值的环路,存在那么这个图就没有解,否则就有解。
图是这样的,依旧是把字母按字母表的顺序转换成数字了。
代码
在图算法里面,如果用矩阵来做,其实数组还是挺好用的,这里我都很少用结构体了,写起来麻烦而且涉及到各种数据类型的不匹配。
#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 100
#define INF 0x3f3f3f3f
int map[N][N]; //储存weight的二维数组
int currentDistance[N] ; //结点当前的distance,过一会可能就变了。这是用于作比较的数组
int parent[N] ; //这个数组在我的程序里实际上是没用的,但是还是给他维护一下吧,这是正向的思维,寻找新的parent
int son[N] ; //这个数组的功能是把路径给输出来,son数组是parent数组的逆数组
int i, j,k;
int edgeNum; //边的条数
int vertexNum; //结点的个数
bool BELLMAN_FORD(int s)
{
for (i = 0; i < N; i++) //初始化数组
{
currentDistance[i] = INF;
parent[i] = -1;
son[i] = -1;
}
currentDistance[s] = 0;
for (k = 1; k < edgeNum; k++) //对每条边进行V-1次处理
{
for (i = 0; i < N; i++) //松弛
for (j = 0; j < N; j++)
if (map[i][j] != INF)
{
if (currentDistance[j] > currentDistance[i] + map[i][j])
{
currentDistance[j] = currentDistance[i] + map[i][j];
parent[j] = i;
son[i] = j;
}
}
}
printf("%d,(%d)", s,currentDistance[s]);
for (i = 0; i < N; i++)
{
if (son[s] == i)
{
printf(" %d,(%d)", i, currentDistance[i]);
s = i;
i = 0;
}
}
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
{
if (map[i][j] != INF && currentDistance[j] > currentDistance[i] + map[i][j]) //是否存在权重为负值的环路并返回相应的布尔值
return false;
else
return true;
}
}
int main() {
int s;
printf("输入结点个数:\n");
scanf_s("%d", &vertexNum);
for (int i = 0; i < N; i++) //初始化矩阵为最大值
for (int j = 0; j < N; j++)
map[i][j] = INF;
printf("输入边的条数:\n");
scanf_s("%d", &edgeNum);
printf("输入源结点:\n");
scanf_s("%d", &s);
printf("输入两点和权重(逗号分隔)\n");
int a, b, c;
for (int i = 0; i<edgeNum; i++) {
scanf_s("%d,%d,%d", &a, &b, &c);
map[a][b] = c; //注意无向图在给矩阵赋值的时候是双向的
}
printf("单源最短路径:\n");
BELLMAN_FORD(s);
return 0;
}