看了看最短路径的ford算法,刚看时并没有看懂,我一直想不明白的是在迭代的过程中,每一次都要把每条边,进行松弛(就是判断dist[i]与dist[v]+w[v][i]的情况),我开始的认为是只需要一次的迭代就可以解决的,为什么需要n-1次呢,而且有那么一句话是这样说的,第一次迭代是把将与V0有连接的第一层得到最小值,第二次是将距离V0两条边的点求出来。。。其实在
- if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)
- {
- dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
- pre[edge[j].v] = edge[j].u;
- }
- 的过程中我想的一次就能解决的情况是比较特殊的,因为你不知道这边出来的顺序是怎么样的,但是第一次的迭代肯定能将与V0有一条距离的边得到我们想要的最小值,这样第二次就能保证与V0有两条边距离的点求出,并且保证是最小值。
- 而且ford算法也是有优点在的,他较之前的Djikstra算法有两个好处,一是它可以考虑进去权值为负数的,二,它还可以判断给我们的图中是否存在负环路的能力。
下面贴上该过程的全代码
<span style="font-size:18px;"> #include
#include
using namespace std;
#define MAX 0x3f3f3f3f
#define N 1010
int nodenum, edgenum, original; //点,边,起点
typedef struct Edge //边
{
int u, v;
int cost;
}Edge;
Edge edge[N];
int dis[N], pre[N];
bool Bellman_Ford()
{
for(int i = 1; i <= nodenum; ++i) //初始化
dis[i] = (i == original ? 0 : MAX);
for(int i = 1; i <= nodenum - 1; ++i)
for(int j = 1; j <= edgenum; ++j)
if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)
{
dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
pre[edge[j].v] = edge[j].u;
}
bool flag = 1; //判断是否含有负权回路
for(int i = 1; i <= edgenum; ++i)
if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
{
flag = 0;
break;
}
return flag;
}
void print_path(int root) //打印最短路的路径(反向)
{
while(root != pre[root]) //前驱
{
printf("%d-->", root);
root = pre[root];
}
if(root == pre[root])
printf("%d\n", root);
}
int main()
{
scanf("%d%d%d", &nodenum, &edgenum, &original);
pre[original] = original;
for(int i = 1; i <= edgenum; ++i)
{
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
}
if(Bellman_Ford())
for(int i = 1; i <= nodenum; ++i) //每个点最短路
{
printf("%d\n", dis[i]);
printf("Path:");
print_path(i);
}
else
printf("have negative circle\n");
return 0;
}
</span>