单源点最短路径Dijkstra和Bellmanford
Dijikstra算法精髓在于维护了两个集合s和v,而这也是实际编程中实现起来比较头疼的事情,我的做法是把每个节点都设置成一个结构体,里面有个状态变量,为‘s’则意味着它在S集合当中。
另外还有很多小的细节需要注意
- 在C语言中实现时初始的邻接矩阵表示(没有的边可以用很大的数来表示)
- 在松弛过程中注意不要局限于在V集合中的那些点,在S集合中的点也有可能被松弛(但是这种情况只会出现在图中有零环的情况,下面一个例子就是这样的)
- 选取值最小的点。下例由于点数少,所以我直接两个for循环找最小,如果图大的话就要选用好的算法了
代码块
代码块语法遵循标准markdown代码,例如:
#include<stdio.h>
#include<stdlib.h>
#define n 5
#define m 9999
//结构体数组,node代表着一个结点,d为源点到此点的距离,state代表它是集合s中的还是v中的
struct {
int d;
char state;
}node[n];
//松弛,代表把j加入到S后 应该做的一系列动作
void relax(int j,int A[5][5]){
for(int i=0;i<n;i++){
if((A[j][i]!=m)&&(node[j].d+A[j][i]<node[i].d))
{node[i].d=node[j].d+A[j][i];}
}
}
int main()
{
//先初始化node[n];
int min,i,j;
int s=0;
node[0].d=0;
node[0].state='v';
for(int i=1;i<n;i++){
node[i].d=m;
node[i].state='v';
}
int A[5][5]={{m,-1,3,m,m},{m,m,3,2,2},{m,m,m,m,m},{m,1,5,m,m},{m,m,m,-3,m}};
//然后对d进行排序,把最小的那个state记作s,表示它不在松弛范围内
while(s!=n){ //一直到所有的state为s为止
//下面两个for是为了找到v中最小的那个
for(i=0;i<n;i++){
if(node[i].state=='v') {
min=node[i].d;
j=i;
break;
}
}
for(i=0;i<n;i++){
if((node[i].state=='v')&&(node[i].d<min) )
{
min=node[i].d;j=i;
}
}
//j目前记录了最小的d值,下面把state变s,且把s集合的记录数加1
node[j].state='s';s++;
relax(j,A);
}
for(int i=0;i<n;i++){
printf("%d ",node[i].d);
}
//然后输出数组d[i];就是单元点A到各个点的最短路径。
Bellmanford
#include<stdio.h>
#include<stdlib.h>
#define n 5
#define m 9999
//Bellman-Ford算法
int main(){
int t=1;
int A[5][5]={{m,-1,3,m,m},
{m,m,3,2,2},
{m,m,m,m,m},
{m,1,5,m,m},
{m,m,m,-3,m}};
int d[n]={0,m,m,m,m};
do{
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(A[i][j]!=m) {
if(d[j]>d[i]+A[i][j])
d[j]=d[i]+A[i][j];
}
}
}
t++;
}while(t<=n-1);
for(int i=0;i<n;i++){
printf("%d ",d[i]);
}
}