Cod sursa(job #1897195)

Utilizator diacacmmDiac Adrian diacacmm Data 1 martie 2017 11:28:30
Problema Algoritmul lui Dijkstra Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.14 kb
/*
Dijkstra cu heapuri

Complexitate: O( m * log(n) )

Observatii:
- Nodul de start a fost considerat nodul 1.
- Prima pozitie a heapului este considerata 1. Astfel, tatal nodului i va fi i/2, fiul stanga i*2, iar fiul dreapta i*2+1;
- Vectorul d memoreaza distantele minime de la 1
- Vectorul h memoreaza heap ul
- Vectorul t retine drumul de la 1 la un nod oarecare folosind memorarea de tip tata
- Vectorul poz retine pozitia fiecarui varf in heap
- La fiecare pas al algoritmului ne trebuie minimul din vectorul d si atunci intervine ideea de a organiza graful intr un minheap
pentru ca obtinerea minimului sa se faca in O(1)
- ideea minheapului este ca varful parinte sa fie mai mic decat descendentii lui, astfel cel mai mic varf va fi primul
*/

#include<fstream>
#define dim 50002
#define inf 1<<30

using namespace std;

struct nod
{
    int info,cost;
    nod*urm;
}*a[dim],*q; //Folosim listele pentru a evita gasirea nodurilor vecine in O(n)

ifstream fin("dijkstra.in");
ofstream fout("dijkstra.out");

int m,n,h[dim],d[dim],t[dim],poz[dim],varf;

void adauga(int x,int y,int c)
{
    //facem adaugare la stanga pentru a comasa adaugare si creare
    nod *nou=new nod;
    nou->info=y;
    nou->cost=c;
    nou->urm=a[x];
    a[x]=nou;
}

void swap(int i,int j)
{
    int x;
    x=h[i];
    h[i]=h[j];
    h[j]=x;
    x=poz[h[i]];
    poz[h[i]]=poz[h[j]];
    poz[h[j]]=x;
    /*Odata cu interschimbarea a doua elemente din heap trebuie sa interschimbam si pozitiile lor in vectorul de pozitii*/
}
void heapup(int i)
{
    //atunci cand actualizez distanta varful respectiv din heap poate sa devina mai mic decat parintele
    //si atunci il avansam prin interschimbare
    if(d[h[i/2]]<d[h[i]])
        return;
    swap(i,i/2);
    heapup(i/2);
}
void heapdown(int i)
{
    //cand interschimb primul varf al heapului cu ultimul, valoarea adusa pe prima pozitie poate fi mare si atunci
    //pentru a pastra prop de heap il retrogradez in stanga sau dreapta cat este nevoie
    int st,dr;
    if(i*2>m)
        return;
    st=d[h[i*2]];
    if(i*2+1<=m)
        dr=d[h[i*2+1]];
    else
        dr=st+1;
    if(st<dr)
    {
        if(d[h[i]]<=st)
            return;
        swap(i,2*i);
        heapdown(i*2);
    }
    else
    {
        if(d[h[i]]<=dr)return;
        swap(i,2*i+1);
        heapdown(2*i+1);
    }
}
void citire()
{
    int i,x,y,c;
    fin>>n>>m;
    for(i=1;i<=m;++i)
    {
        fin>>x>>y>>c;
        adauga(x,y,c);
    }
}

void drum(int i)
{
    if(t[i]!=0)
    {
        drum(t[i]);
        fout<<i<<" ";
    }
    else
        fout<<"\n";//afisez un enter la final
}

int main()
{
    int i;
    citire();
    for(i=1;i<=n;i++)
    {
            d[i]=inf; /*Initial toate distantele sunt considerate infinit*/
            h[i]=i;
            poz[i]=i;
    }
    m=n;
    d[1]=0;/*Toate distantele mai putin cea a nodului initial, bineinteles*/
    d[0]=-1;/*Acest lucru este oarecum util pentru cazurile cand costul dintre doua varfuri este nul si considerati 1 prima pozitie a heapului*/
    for(i=0;i<n;i++)
    {
        varf=h[1];/*Desemnam nodul pe care il expandam*/
        swap(1,m); /*Dupa ce am ales nodul pe care il vom optimiza cu dijkstra, (cel din varful heapului) il mutam la coada*/
        m--; /* si scadem lungimea heapului, astfel incat algoritmul va lasa nodul curent in pace*/
        heapdown(1); /*Reordonam arborele ca sa ramane minheap*/
        for(q=a[varf];q!=NULL;q=q->urm) /*Luam fiecare varf vecin cu cel pe care il expandam*/
            if(d[q->info]>d[varf]+q->cost) /*Verificam daca ajungem la el cu un cost mai bun*/
            {
                d[q->info]=d[varf]+q->cost;/*Daca da, actualizam distanta, */
                t[q->info]=varf;/* desemnam nodul curent ca fiind noul tata al varfului pe care l-am actualizat*/
                heapup(poz[q->info]);/*si reordonam heapul*/
            }
    }
    //afisarea drumurilor de la 1 (daca nu exista se afiseaza 0)
    for(i=2;i<=n;++i)
        if(d[i]==inf)
            fout<<0<<" ";
        else
            fout<<d[i]<<" ";
    fout<<"\n";
    return 0;
}