虽然写这个博客主要目的是为了给我自己做一个思路记忆录,但是如果你恰好点了进来,那么先对你说一声欢迎。我并不是什么大触,只是一个菜菜的学生,如果您发现了什么错误或者您对于某些地方有更好的意见,非常欢迎您的斧正!
最短路径的最优子结构
最短路径的子路径也是最短路径。
负权重的边
权重为负数的边。(我的理解:大概知道这个就可以了)
环路
最短路径既不能包含正的环路,也不能包含负的环路。(正的环路,我觉得正常人想走最短的路,都不会在那里打圈,除非路就是圆的;负环路你多绕几圈,最后权重想变多小变多小,就很没意思。)
最短路径的表示
每个节点保持一个前驱属性v.π,指向它的前一个结点。(这样可以串成一串)
松弛操作
说白了就是就是检查一下绕小路会不会更近。
v.d:表示s到v的最短路径估计
接下来书中还有一堆性质,我就放图,我自己也没看,感觉很每意思,就是感觉把一些简单的东西说的很复杂,显得十分高大上。
24.1Bellman-Ford算法(贝尔曼-福特算法)
我的思路:
这边为什么要先对点循环,然后再套一个对边的循环松弛呢?因为第一次松弛的时候,部分地方还不是最短路径。这边思路真的不是很好描述:最好的办法就是自己按照它的流程走一遍!
24.2有向无环图中的单源最短路径问题
1、对有向无环图进行拓扑排序
2、再进行Bellman类似操作
这一章我模棱两可地看了看,emmm不知道它到底要讲些什么,如果你知道的话,请告诉我,谢谢!那么我就要跳过这部分了。
24.3Dijkstra算法(迪杰斯特拉算法)
Dijkstra算法解决的是带权重的有向图上单源最短路径问题,要求所有边权重大于0 。
我的感觉:它就是一个改进的Prim算法。
我的思路:
1、每个点都有一个mark属性标志着是否已经在路径中
2、将边从小排到大
3、如果点没有全部加入到路径中,从小到大遍历每条边,如果边的起点在路径中,边的终点没在路径中,就把终点的前驱设置为起点,同时终点的mark属性变为true
4、开始重新遍历边
24.4差分约束和最短路径
24.5最短路径性质的证明
四五两章都非常的理论,我就不看了,真的很讨厌这种看的头疼又看不懂的东西。
以下就是代码部分了(建议粘贴到自己的编辑器中运行)
Bellman.h
#pragma once
#define BELLV 5/*点的数量*/
#define BELLE 10/*边的数量*/
/*点*/
typedef struct BellV
{
char data;/*数据*/
int d;/*源结点到该点的最短距离*/
BellV* π;/*前驱结点*/
}Bellv;
/*边*/
typedef struct
{
Bellv* start;/*起点*/
Bellv* end;/*终点*/
int w;/*权重*/
}Belle;
/*图*/
typedef struct
{
Bellv* v[BELLV];/*点集*/
Belle* e[BELLE];/*边集*/
}Bellg;
/*初始化*/
void InitBell(Bellg* &G, Bellv* root);
/*松弛操作*/
void BellRelax(Bellv* u, Bellv* v, int w);
/*Bellman算法*/
bool Bellman(Bellg* &G, Bellv* root);
/*打印路径*/
void BellPrint(Bellv *root, Bellv *end);
/*测试函数*/
void TestBellman();
Bellman.cpp
#include "Bellman.h"
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
/*初始化*/
void InitBell(Bellg* &G,Bellv* root)
{
for (int i = 0; i < BELLV; i++)
{
G->v[i]->d = 100;/*我们假装这个100就是∞*/
G->v[i]->π = NULL;/*前驱为空*/
}
root->d = 0;/*源结点*/
}
/*松弛操作*/
void BellRelax(Bellv* u, Bellv* v, int w)
{
if (v->d > u->d + w)
{
v->d = u->d + w;
v->π = u;
}
}
/*Bellman算法*/
bool Bellman(Bellg* &G,Bellv* root)
{
InitBell(G, root);
int i, j;
for (i = 0; i < BELLV; i++)/*对顶点进行遍历*/
{
if (G->v[i] != root)/*如果不是根结点*/
{
for (j = 0; j < BELLE; j++)
BellRelax(G->e[j]->start, G->e[j]->end, G->e[j]->w);
}
}
for (i = 0; i < BELLE; i++)/*检测是否有负回路*/
if (G->e[i]->end->d > G->e[i]->start->d + G->e[i]->w)
return false;
return true;
}
/*打印路径*/
void BellPrint(Bellv *root, Bellv *end)
{
Bellv* tmp = end;
if (tmp != root)
{
BellPrint(root, tmp->π);
cout << tmp->data << " ";
}
}
/*测试函数*/
void TestBellman()
{
/*图*/
Bellg* G = new Bellg();
/*点集*/
Bellv* s = new Bellv(); s->data = 's';
Bellv* t = new Bellv(); t->data = 't';
Bellv* x = new Bellv(); x->data = 'x';
Bellv* y = new Bellv(); y->data = 'y';
Bellv* z = new Bellv(); z->data = 'z';
G->v[0] = s; G->v[1] = t;
G->v[2] = x; G->v[3] = y; G->v[4] = z;
int i;
for (i = 0; i < BELLE; i++)
G->e[i] = new Belle();
G->e[0]->start = s; G->e[0]->end = t; G->e[0]->w = 6;
G->e[1]->start = s; G->e[1]->end = y; G->e[1]->w = 7;
G->e[2]->start = t; G->e[2]->end = x; G->e[2]->w = 5;
G->e[3]->start = t; G->e[3]->end = y; G->e[3]->w = 8;
G->e[4]->start = t; G->e[4]->end = z; G->e[4]->w = -4;
G->e[5]->start = x; G->e[5]->end = t; G->e[5]->w = -2;
G->e[6]->start = y; G->e[6]->end = x; G->e[6]->w = -3;
G->e[7]->start = y; G->e[7]->end = z; G->e[7]->w = 9;
G->e[8]->start = z; G->e[8]->end = s; G->e[8]->w = 2;
G->e[9]->start = z; G->e[9]->end = x; G->e[9]->w = 7;
Bellv* root = s;
if (Bellman(G, root))
{
for (i = 0; i < BELLV; i++)
{
if (i != 0)
{
cout << root->data << " ";
BellPrint(root, G->v[i]);
cout << endl;
}
}
}
else
cout << "Error!";
}
主函数
#include "Bellman.h"
#include <stdio.h>
int main()
{
TestBellman();
getchar();
getchar();
return 0;
}
运行结果
Dijstra.h
#pragma once
#define DIJV 5/*点的数量*/
#define DIJE 10/*边的数量*/
/*点*/
typedef struct dijV
{
char data;/*数据*/
dijV* π;/*前驱*/
bool mark;/*标记是否已经加入到最短路径*/
}dijv;
/*边*/
typedef struct
{
dijv* start;/*起点*/
dijv* end;/*终点*/
int w;/*权重*/
}dije;
/*图*/
typedef struct
{
dijv* v[DIJV];/*点集*/
dije* e[DIJE];/*边集*/
}dijg;
/*比较函数*/
bool DijCmp(dije* x, dije* y);
/*Dijkstra算法*/
void Dijkstra(dijg* &g, dijv* root);
/*打印路径*/
void DijPrint(dijv *root, dijv *end);
/*测试函数*/
void TestDijkstra();
Dijstra.cpp
#include "Dijstra.h"
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>/*sort排序函数所需头文件*/
#include<iostream>
using namespace std;
/*比较函数*/
bool DijCmp(dije* x, dije* y)
{
return x->w < y->w;/*从小到大*/
}
/*Dijkstra算法*/
void Dijkstra(dijg* &g,dijv* root)
{
int i, j;
for (i = 0; i < DIJV; i++)
{
g->v[i]->mark = false;/*没有被加入最短路径中*/
g->v[i]->π = NULL;
}
root->mark = true;
sort(g->e, g->e + DIJE, DijCmp);/*按权重排序*/
j = 0;
while (j < DIJV - 1)/*还有点没有被选中*/
{
for (i = 0; i < DIJE; i++)
{
if (g->e[i]->start->mark && !(g->e[i]->end->mark))/*起点在路径中,终点没有*/
{
g->e[i]->end->mark = true;
g->e[i]->end->π = g->e[i]->start;
j++;
i = 20;/*结束这个for循环*/
}
}
}
}
/*打印路径*/
void DijPrint(dijv *root, dijv *end)
{
dijv* tmp = end;
if (tmp != root)
{
DijPrint(root, tmp->π);
cout << tmp->data << " ";
}
}
/*测试函数*/
void TestDijkstra()
{
int i;
dijg* g = new dijg();/*图*/
dijv* s = new dijv(); s->data = 's';
dijv* t = new dijv(); t->data = 't';
dijv* x = new dijv(); x->data = 'x';
dijv* y = new dijv(); y->data = 'y';
dijv* z = new dijv(); z->data = 'z';
g->v[0] = s; g->v[1] = t;
g->v[2] = x; g->v[3] = y; g->v[4] = z;
for (i = 0; i < DIJE; i++)
g->e[i] = new dije();
g->e[0]->start = s; g->e[0]->end = t; g->e[0]->w = 10;
g->e[1]->start = s; g->e[1]->end = y; g->e[1]->w = 5;
g->e[2]->start = t; g->e[2]->end = x; g->e[2]->w = 1;
g->e[3]->start = t; g->e[3]->end = y; g->e[3]->w = 2;
g->e[4]->start = x; g->e[4]->end = z; g->e[4]->w = 4;
g->e[5]->start = y; g->e[5]->end = t; g->e[5]->w = 3;
g->e[6]->start = y; g->e[6]->end = x; g->e[6]->w = 9;
g->e[7]->start = y; g->e[7]->end = z; g->e[7]->w = 2;
g->e[8]->start = z; g->e[8]->end = s; g->e[8]->w = 7;
g->e[9]->start = z; g->e[9]->end = x; g->e[9]->w = 6;
dijv* root = s;
Dijkstra(g, s);
for (i = 0; i < DIJV; i++)
{
if (i != 0)
{
cout << root->data << " ";
DijPrint(root, g->v[i]);
cout << endl;
}
}
}
主函数
#include "Dijstra.h"
#include <stdio.h>
int main()
{
TestDijkstra();
getchar();
getchar();
return 0;
}
运行结果