Вы находитесь на странице: 1из 10

Технический Университет Молдовы

Departament ISA

Отчет
по лабораторной работе № 4

Тема: Поиск минимального и максимального пути в


графе с помощью алгоритма Беллмана Форда.

Выполнила: студентка гр CIM-161


Раковец Элита
Проверила : Тихолаз Тамара

Кишинёв 2017
Цель работы: Изучение алгоритмов поиска минимального пути в
графе. Разработка программы, реализующей данные алгоритмы
поиска минимального пути в взвешенном графе.

Алгоритм Беллмана-Форда
Алгоритм Беллмана-Форда решает задачу о кратчайших весах из одной
вершины для случая, когда весам ребер разрешено быть отрицательными.
Этот алгоритм возвращает TRUE, если в графе нет цикла отрицательного веса,
достижимого из исходной вершины, и FALSE, если таковой цикл имеется. В
первом случае алгоритм находит кратчайшие пути и их веса; во втором случае
кратчайших путей (по крайней мере, для некоторых вершин) не существует.
Поиск минимального пути по алгоритму Форда

Алгоритм Форда позволяет от какой-либо исходной вершины Xi


определить минимальный путь до произвольной вершины Xj графа G.
Алгоритм Форда состоит из следующих шагов:
1) Каждой вершине Xi графа G ставятся в соответствие
максимально возможные для данной задачи числа Hi;
2) На втором шаге вычисляются разности Hj-Hi для каждой вершины
Xi, где Hj - вес вершины, в которую ведет дуга (Xi,Xj). Здесь возможны
три случая: Hj - Hi < Lij, Hj-Hi=Lij, Hj-Hi>Lij,
где Lij - вес дуги, ведущей из вершины Xi в вершину Xj.
Случай, когда Hj-Hi>Lij позволяет нам уменьшить расстояние между
вершинами Xi и Xj благодаря следующим преобразованиям: Hj-Hi>Lij,
Hj > Lij + Hi, отсюда принимаем: Hj=Hi+Lij.
Второй шаг выполняется до тех пор, пока еще существуют пары (i,j),
для которых выполняется неравенство Hj-Hi>Lij.
По окончанию второго этапа метки вершин позволяют нам
определить значение минимального пути из исходной в конечную
вершину;
3) На третьем этапе происходит определение минимального пути
при помощи обратного хода от конечной вершины к начальной, причем
для вершины Xj предшествующей будет вершина Xi, если для этой
пары выполняется Hj-Hi=Lij. Если существует несколько таких пар, то
выбирается любая из них.
Алгоритм Белмана - Калаба

Использование алгоритма Беллмана-Калаба позволяет нам ускорить поиск


минимального пути между произвольной заданной парой вершин.
На первом этапе заданному графу ставится в соответствие взвешенная матрица
смежности M. Матрица формируется по следующим правилам:
1) M(i,j)=Lij, если существует дуга, ведущая из Xi в Xj, где Lij - вес этой дуги;
2) M(i,j)=max, где max - максимально возможное число для данной задачи, если не
существует дуги, ведущей из вершины Xi в Xj;
3) M(i,j)=0, если i=j.
На втором этапе строится вектор V0 по следующим правилам:
1) V0(i)=Lin, если существует дуга, ведущая из вершины Xi в вершину Xn, где Xn -
конечная заданная вершина, для которой ищется минимальный путь, Lin - вес этой дуги;
2) V0(i)=max, где max - максимально возможное число для данной задачи, если не
существует дуги, ведущей из вершины Xi в Xn;
3) V0(i)=0, если i=j.
На k-той итерации строится вектор Vk по следующим правилам:
1) Vk(i)=min{Vk-1(j)+Lij}, где i=1..(n-1),j=1..n;
i<>j
2) Vk(n) = 0.
Итерации прекращаются, когда мы получаем вектор, равный предыдущему, т.е.Vk=Vk-
1.
После прекращения процесса элемент вектора Vk, имеющий наименьшее значение, не
равное нулю, дает нам длину минимального пути между заданной парой вершин.

Определение:
Ориентированный граф (сокращенно орграф) G = (V, E) состоит из множества
вершин V и множества дуг E. Вершины также называют узлами, а дуги –
ориентированными ребрами. Дуга представима в виде упорядоченной пары
вершин (v, w), где вершина v называется началом, а w – концом дуги.

Код программы:
#define MAX 30000
using namespace std;
struct List{
int v;
int w;
struct List *next;
};
struct Graph{
int h;
int p;
struct List *first;
struct List *last;
}*G;
int maxFlag;
int N;
int V;
void Ford();
void BelmanKalab();
void PathFord(int );
void Menu();
void ListAdj();
void FreeList();
int main()
{
Menu();
return 0;
}
void BellmanKalab()
{
int i,j,k;
struct List *c;
int **M=(int **)malloc(N*sizeof(int *));
int *VK=(int *)malloc(N*sizeof(int ));
int *VK_1=(int *)malloc(N*sizeof(int ));
int *t,f=1;
int *P=(int *)malloc(N*sizeof(int ));
for(i=0;i<N;i++)
M[i]=(int *)malloc(N*sizeof(int));
for(i=0;i<N;i++)
for(j=0;j<N;j++)
M[i][j]=(i==j)?0:MAX;
for(i=0;i<N;i++){
c=G[i].first;
while(c!=G[i].last){
if(maxFlag){
M[i][c->v]= -(c->w);
} else{
M[i][c->v]=c->w;
}
c=c->next;
}
}
printf("Введите конечную вершину: ");
scanf("%d",&V);
V--;
for(i=0;i<N;i++){
VK_1[i]=M[i][V];
P[i]=-1;
}
while(f){
for(i=0;i<N;i++)
VK[i]=MAX;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
if(i!=j && VK[i]>VK_1[j]+M[i][j]){
VK[i]=VK_1[j]+M[i][j];
P[i]=j;
}
VK[V]=0;
for(i=0;i<N && VK[i]==VK_1[i];i++);
f=(i==N)?0:1;
t=VK_1;
VK_1=VK;
VK=t;
}
for(i=0;i<N;i++){
printf("\nПуть от %d до %d равен ", i+1, V+1);
if(VK_1[i] > 25000)
printf("Не существует.");
else {
for(k=i,j=0;j<N && P[k]!=-1 && k!=V;j++){
printf("->%d",k+1);
k=P[k];
}
printf("->%d",V+1);
if(maxFlag){
printf(" с длиной равной %d.", -VK_1[i]);
} else {
printf(" с длиной равной %d.", VK_1[i]);
}
}
}
for(i=0;i<N;i++)
free(M[i]);
free(P);
free(M);
printf("\nV : ");
free(VK);
if(maxFlag) {
for(i = 0; i < N; i++){
if(VK_1[i] > 25000) {
printf(" -inf ");
} else {
printf(" %d ", -VK_1[i]);
}
}
} else {
for(i = 0; i < N; i++){
if(VK_1[i] == MAX) {
printf(" inf ");
} else {
printf(" %d ", VK_1[i]);
}
}
}
free(VK_1);
}
void Ford()
{
int *VK = (int *)malloc(N * sizeof(int));
int i,f=1;
for(i = 0; i < N; i++)
VK[i] = 50000;
struct List *c;
if(G==NULL)
return;
for(i=0;i<N;i++){
G[i].p=-1;
G[i].h=MAX;
}
printf("Введите стартовую вершину: ");
scanf("%d",&V);
G[--V].h=0;
while(f){
f=0;
for(i=0;i<N;i++){
c=G[i].first;
if(maxFlag){
while(c!=G[i].last){
if(G[c->v].h>G[i].h-c->w){
G[c->v].h=G[i].h-c->w;
G[c->v].p=i;
f=1;
}
c=c->next;
}
} else{
while(c!=G[i].last){
if(G[c->v].h>G[i].h+c->w){
G[c->v].h=G[i].h+c->w;
G[c->v].p=i;
f=1;
}
c=c->next;
}
}
}
}
for(i=0;i<N;i++){
printf("\nПуть от %d до %d равен ",V+1,i+1);
if(G[i].h==MAX)
printf("Не существует.");
else{
PathFord(i);
if(maxFlag){
printf(" с длиной равной %d.", -G[i].h);
} else {
printf(" с длиной равной %d.", G[i].h);
}
VK[i] = G[i].h;
}
}
printf("\nV : ");
if(maxFlag){
for(i = 0; i < N; i++){
if(VK[i] > 30000 || VK[i] < -30000)
printf(" -inf ");
else
printf(" %d ", -VK[i]);
}
} else {
for(i = 0; i < N; i++){
if(VK[i] > 30000 || VK[i] < -30000)
printf(" inf ");
else
printf(" %d ", VK[i]);
}
}
}
void PathFord(int v)
{
if(v!=V)
PathFord(G[v].p);
printf("->%d",v+1);
}
void Menu()
{
int i;
char ch;
printf("\n--------------------\n");
printf("1.Ввести граф\n");
printf("2.Минимальный путь по алгоритму Форда\n");
printf("3.Максимальный путь по алгоритму Форда\n");
printf("4.Минимальный путь по алгоритму Белмана-Калаба\n");
printf("5.Максимальный путь по алгоритму Белмана-Калаба\n");
printf("0.Выход\n");
do
scanf("%c", &ch);
while(ch<'0' || ch>'7');
printf("\n--------------------\n");
switch (ch)
{
case '1': ListAdj();break;
case '2': maxFlag = 0; Ford();scanf("%c", &ch);break;
case '3': maxFlag = 1; Ford();scanf("%c", &ch);break;
case '4': maxFlag = 0;BelmanKalab();scanf("%c", &ch);break;
case '5': maxFlag = 1;BelmanKalab();scanf("%c", &ch);break;
case '0': FreeList();return;
}
Menu();
}
void ListAdj()
{
int i,v,w;
struct List *c;
if(G)
FreeList();
printf("Введите колличество вершин: ");
scanf("%d",&N);
G=(Graph *)malloc(N*sizeof(Graph));
printf("\n");
for(i=0;i<N;i++){
printf("%d->",i+1);
G[i].first=(List *)malloc(sizeof(List));
G[i].last=G[i].first;
G[i].last->next=NULL;
G[i].last->v=-1;
scanf("%d",&v);
while(v){
scanf("%d",&w);
G[i].last->v=v-1;
G[i].last->w=w;
G[i].last->next=(List *)malloc(sizeof(List));
G[i].last=G[i].last->next;
G[i].last->next=NULL;
G[i].last->v=-1;
scanf("%d",&v);
}
}
}
void FreeList()
{
struct List *c,*t;
while(N--){
c=G[N].first;
while(c!=G[N].last){
t=c->next;
free(c);
c=t;
}
}
free(G);
}
Как работает программа:

Количество вершин: 5

1->2
9
3
3
4
8
0
2->5
14
0
3->2
3
5
11
0
4->3
3
5
18
0
5->0
1.Ввести граф
2.Минимальный путь по алгоритму Форда
3.Максимальный путь по алгоритму Форда
4.Минимальный путь по алгоритму Белмана-Калаба
5.Максимальный путь по алгоритму Белмана-Калаба
0.Выход
2

--------------------
Введите стартовую вершину: 1

Путь от 1 до 1 равен ->1 с длиной равной 1.


Путь от 1 до 2 равен ->1->3->2 с длиной равной 9.
Путь от 1 до 3 равен ->1->3 с длиной равной 3.
Путь от 1 до 4 равен ->1->4 с длиной равной 8.
Путь от 1 до 5 равен ->1->3->5 с длиной равной 11.
V : 1 9 3 8 11
--------------------
1.Ввести граф
2.Минимальный путь по алгоритму Форда
3.Максимальный путь по алгоритму Форда
4.Минимальный путь по алгоритму Белмана-Калаба
5.Максимальный путь по алгоритму Белмана-Калаба
0.Выход
5

--------------------
Введите конечную вершину: 5

Путь от 1 до 5 равен ->1->4->3->2->5 с длиной равной 20.


Путь от 2 до 5 равен ->2->5 с длиной равной 1.
Путь от 3 до 5 равен ->3->2->5 с длиной равной 15.
Путь от 4 до 5 равен ->4->3->2->5 с длиной равной 19.
Путь от 5 до 5 равен ->5 с длиной равной 5.
V : 20 1 15 19 5

Вывод: На этой лабораторной работе, я закрепила алгоритм поиска минимального пути в


графе. После чего, разработала программу, реализующую данные алгоритмы поиска
минимального пути в взвешенном графе. Именно такие алгоритмы используются при решении
задач.