Algoritmul lui Djikstra

 

Fie G=(V, E) un graf orientat, unde V are n elemente (n varfuri) si E are m elemente (m  arce).   Se cunosc costurile arcelor.

Matricea costurilor:

0      1      9           3

     0      7      3     

          0          

1           2      0     

     4           2      0

 
                                                                                             

 

                               1                                      7

                                       4             3            9

 

 

                          3                     1                      2

 

                                               2

 

 

 

 

Ne propunem sa determinam costul minim de la un varf la toate celelalte varfuri. Fie acesta varful 1.

 

Vom utiliza 3 vectori :

 

0

1

9

3

 

 

 

1

0

0

0

0

 

 

 

0

1

1

0

1

 

 

Algoritmul :

 

Matricea costurilor:

0      1      9           3

     0      7      3     

          0          

1           2      0     

     4           2      0

 
                                                                      

 

                               1                                      7

                                         4             3            9                                 

 

 

                          3                     1                       2

 

                                               2

 

 

In vectorul d se incarca costurile de la r la fiecare dintre celelalte varfuri

 

Vectorul  d :

0

1

9

3

 

 

Vectorul s :

1

0

0

0

0

 

 

Vectorul t :

0

1

1

0

1

 

 

 

Se determina cel mai apropiat varf de varful 1 din vectorul d (valoarea minima din d) :

0

1

9

3

 

 

Acesta este varful 2 care se adauga la drum :

                                   :

 


                               1                                      7

                                       4             3            9                       

 

 

                          3                     1                       2

 

                                               2

 

min=1, vf=2

se marcheaza in s :

Vectorul s :

1

1

0

0

0

 

 

In continuare se pune problema daca pentru nodurile neadaugate inca nu s-ar putea realiza imbunatatiri ale lungimii drumurilor prin 2:

 

Adica pentru un varf x daca d[x]>d[vf]+a[vf][x] atunci re realizeaza modificarea efectiv in d si se adauga vf ca fiind predecessor (tata) pentru x:

 

if(d[x]>d[vf]+a[vf][x])

       { d[x]=d[vf]+a[vf][x];

          t[x]=vf;          

       }

 

 

 

 


      1                                      7

                                       4             3            9                       

 

 

                          3                     1                       2

 

                                               2

 

Se pot imbunatati drumurile de la 1 la 3 prin 2 si de la 1 la 4 prin 2. Vectorii devin :

Vectorul  d :

0

1

8

4

3

 

 

Vectorul s :

1

1

0

0

0

 

 

Vectorul t :

0

1

2

2

1

 

 

Mai sunt de adaugat varfurile 3,4, 5. Acestea se pot « agata » de varfurile adaugate (selectate) fie 1 fie 2.

 

Se procedeaza la fel : se determina cel mai apropiat varf : min =3 si vf=5

Vectorul  d :

0

1

8

4

3

 

 

Se selecteaza in s : s[vf]=1:

Vectorul s :

1

1

0

0

1

 

 

Dar nu se mai pot obtine imbunatatiri ale  drumurilor de la 1 la varfurile ramase (3 sau 4) care sa treaca prin 5 prin urmare vectorul t ramane acelasi :

 

Vectorul t :

0

1

2

2

1

 

 

Am afuns la urmatoarea situatie :

 

 

 


      1                                      7

                                       4             3            9                       

 

 

                          3                     1                       2

 

                                               2

 

 

 

Mai sunt de adaugat varfurile 3 si 4.  Varfurile adaugate sunt 1 ,2 si 5

 

Se cauta in continuare cel mai apropiat varf neselectat inca(pentru care in s valoarea este 0). Acesta este 4 :

Min=4, vf=4.

Se adauga la arbore si se obtine :

 

 

 


      1                                      7

                                       4             3            9                       

 

 

                          3                     1                       2

 

                                               2

 

 

Se poate realiza o imbunatatire a drumului de la 1 la 3 prin 4 si se adauga 4

ca parinte pentru 3 iar d[3]=d[4]+a[4][3]=4+2=6

 

 


      1                                      7

                                       4             3            9                       

 

 

                          3                     1                       2

 

                                               2

 

Vectorii devin:

 

Vectorul  d :

0

1

6

4

3

 

 

Vectorul s :

1

1

0

1

1

 

 

Vectorul t :

0

1

4

2

1

 

 

La sfarsit se adauga varful 3:

 

 


      1                                      7

                                       4             3            9                       

 

 

                          3                     1                       2

 

                                               2

 

Practic se obtine arborele (un graf partial):

 

 

 


      1                                 

3

 

1

 
                                                      3                          

 

 


                          3                                               2

 

4

 

5

 
                                              

 

 

Vectorii devin :

Vectorul  d :

0

1

6

4

3

 

 

Vectorul s :

1

1

0

1

1

 

 

Vectorul t :

0

1

4

2

1

 

 

O solutie de implementare :

 

#include<fstream.h>

#include<conio.h>

 

const pinf=1000;

int a[20][20],n,m;

int r;//varful de inceput

int s[100];//vectorul caracteristic - marcheaza cu 1 varfurile selectate

int d[100];//vectorul lungimii drumurilor de la varful r la toate celelelte varfuri

int t[100];//vectorul de tip tata- pentru

 

 

void citire_cost()

{fstream f;

 int i,j,x,y,c;

 f.open("roy.in",ios::in);

 if(f)

   cout<<"deschiderea a reusit";

 else

   cout<<"eroare la deschidere!";

 cout<<endl;

 f>>n>>m;

 //initializare matrice

 for(i=1;i<=n;i++)

    for(j=1;j<=n;j++)

      if(i==j)

             a[i][j]=0;

       else

             a[i][j]=pinf;

  for(i=1;i<=m;i++)

     {f>>x>>y>>c;

      a[x][y]=c;}

}

 

void afisare_mat()

{cout<<endl<<"matricea costurilor"<<endl;

for(int i=1;i<=n;i++)

   {for(int j=1;j<=n;j++)

             if(a[i][j]==pinf)

                cout<<"pinf ";

             else

               cout<<a[i][j]<<"  ";

    cout<<endl;}

}

void afiseaza_vector(int v[100])

{for(int i=1;i<=n;i++)

   cout<<v[i]<<" ";

cout<<endl;}

 

void cauta_min(int &vf)//caut varful cel mai apropiat de r care nu a fost selectat inca

{int min=pinf;

for(int i=1;i<=n;i++)

            if(s[i]==0)

                if(d[i]<min)

                         {min=d[i];

                          vf=i;}

}

 

void imbunatatire_drum(int vf)//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el

{for(int i=1;i<=n;i++)

    if(s[i]==0)

       if(d[i]>d[vf]+a[vf][i])

               {d[i]=d[vf]+a[vf][i];

                t[i]=vf;//il adaug pe vaf ca posibil parinte pentru i

               }

}

 

void drum(int i)

{if(t[i])

            drum(t[i]);

 cout<<i<<" ";

}

 

void main()

{clrscr();

int vf,min;

citire_cost();

afisare_mat();

 

cout<<"nodul de inceput?";

cin>>r; //r=1 in exemplu

for(int i=1;i<=n;i++)

   if(i!=r)

       {d[i]=a[r][i];

       if(a[r][i]!=pinf)

               t[i]=r;

       }

 

for(i=1;i<=n-1;i++)

    {cauta_min(vf);//caut varful cel mai apropiat de r care nu a fost selectat inca

     s[vf]=1;  //il selectez ca fiind vizitat

     imbunatatire_drum(vf);//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el

    }

 

cout<<endl;

cout<<"vectorul drum: "<<endl;

afiseaza_vector(d);

cout<<"vectorul critic: "<<endl;

afiseaza_vector(s);

cout<<"vectorul de tati: "<<endl;

afiseaza_vector(t);

 

for(i=1;i<=n;i++)

   if(i!=r)

      if(t[i]!=0)//daca vectorul a fost adaugat la arbore

             {cout<<"drumul de la "<<r<<" la "<<i<<" este :"<<endl;

             drum(i);

             cout<<endl<<"si are lungimea "<<d[i]<<endl<<endl;}

      else

             cout<<"nu exista drum de la "<<r<<" la "<<i<<endl;

getch();

}

 

Aplicatie :

 

/*sa se determine drumul minim de la x la y cu maxim k noduri impare*/

#include<fstream.h>

 

#include<conio.h>

 

 

 

const pinf=1000;

 

int a[20][20],n,m,k;

 

int r;//varful de inceput

 

int s[100];//vectorul caracteristic - marcheaza cu 1 varfurile selectate

 

int d[100];//vectorul lungimii drumurilor de la varful r la toate celelelte varfuri

 

int t[100];//vectorul de tip tata- pentru

 

 

 

 

 

void citire_cost()

 

{fstream f;

 

 int i,j,x,y,c;

 

 f.open("test1.txt",ios::in);

 

 if(f)

 

   cout<<"deschiderea a reusit";

 

 else

 

   cout<<"eroare la deschidere!";

 

 cout<<endl;

 

 f>>n>>m;

 

 //initializare matrice

 

 for(i=1;i<=n;i++)

 

    for(j=1;j<=n;j++)

 

      if(i==j)

 

             a[i][j]=0;

 

       else

 

             a[i][j]=pinf;

 

  for(i=1;i<=m;i++)

 

     {f>>x>>y>>c;

 

      a[x][y]=c;}

 

}

 

 

 

void afisare_mat()

 

{cout<<endl<<"matricea costurilor"<<endl;

 

for(int i=1;i<=n;i++)

 

   {for(int j=1;j<=n;j++)

 

             if(a[i][j]==pinf)

 

                cout<<"pinf ";

 

             else

 

               cout<<a[i][j]<<"  ";

 

    cout<<endl;}

 

}

 

void afiseaza_vector(int v[100])

 

{for(int i=1;i<=n;i++)

 

   cout<<v[i]<<" ";

 

cout<<endl;}

 

 

 

void cauta_min(int &vf)//caut varful cel mai apropiat de r care nu a fost selectat inca

 

{int min=pinf;

 

for(int i=1;i<=n;i++)

 

            if(s[i]==0)

 

                if(d[i]<min)

 

                                    {min=d[i];

 

                                     vf=i;}

 

}

 

 

int verific(int i)

{if(t[i])

   return i%2+verific(t[i]);

 else

    return 0;

 

}

 

 

void imbunatatire_drum(int vf)//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el

 

{for(int i=1;i<=n;i++)

 

    if(s[i]==0)

 

       if(d[i]>d[vf]+a[vf][i])

 

                   {int x;

                   x=t[i];

                   t[i]=vf;

                   int k1=verific(i)+r%2;

                   if(k1<=k)

                            d[i]=d[vf]+a[vf][i];

                   else

                         t[i]=x;

 

 

                   }

 

}

 

 

 

void drum(int i)

 

{if(t[i])

            drum(t[i]);

 cout<<i<<" ";

 

}

 

 

 

void main()

 

{clrscr();

 

int vf,min;

 

citire_cost();

 

afisare_mat();

 

 

 

cout<<"nodul de inceput?";

 

cin>>r;

s[r]=1;

 //r=1 in exemplu

cout<<"k=";

 

cin>>k;

for(int i=1;i<=n;i++)

 

   if(i!=r)

 

       {d[i]=a[r][i];

 

       if(a[r][i]!=pinf)

 

                   t[i]=r;

 

       }

 

 

 

for(i=1;i<=n-1;i++)

 

    {cauta_min(vf);//caut varful cel mai apropiat de r care nu a fost selectat inca

 

     s[vf]=1;  //il selectez ca fiind vizitat

 

     imbunatatire_drum(vf);//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el

 

    }

 

 

 

cout<<endl;

 

cout<<"vectorul drum: "<<endl;

 

afiseaza_vector(d);

 

cout<<"vectorul critic: "<<endl;

 

afiseaza_vector(s);

 

cout<<"vectorul de tati: "<<endl;

 

afiseaza_vector(t);

int y;

cout<<"vf final=";

cin>>y;

cout<<endl;

if(d[y]==pinf)

   cout<<"nu exxista solutie";

else

  cout<<"drumul minim cu maxim k varfuri impare are valoarea "<<d[y];

cout<<endl;

drum(y);

 

 

getch();

 

}