Pagini recente » Cod sursa (job #2899698) | Cod sursa (job #2646075) | Cod sursa (job #720348) | Cod sursa (job #75075) | Cod sursa (job #2961917)
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <fstream>
#include <algorithm>
using namespace std;
ifstream in("fmcm.in");
ofstream out("fmcm.out");
///n -> nr de noduri, m -> nr de muchii, src -> sursa, dest -> destinatia, cost_flux -> costul minim al fluxului maxim
int n, m, src, dest, cost_flux = 0;
///l -> lista de adiacenta
vector<int> l[355];
///cst -> matrice pt costuri, cap -> matrice pt capacitati
int cst[355][355], cap[355][355];
///tata -> vector de tati pentru reconstituirea drumului gasit cu algoritmul lui dijkstra, coada -> vector care retine daca un element se afla sau nu
///in coada pentru a nu introduce duplicate, dist_bf -> distanta determinata de algo lui Belman-Ford, dist -> dist det de algo lui Dijkstra
///astfel incat sa avem numai distante pozitive(Dijkstra nu permite muchii de cost negativ), dist_d -> distanta minima reala det de Dijkstra + Bellman-Ford
int tata[355], coada[355], dist_bf[355], dist_d[355], dist[355];
///q -> coada pt algo lui Bellman-Ford
queue<int> q;
///pq -> coada pt algo lui Dijkstra in care sa memorez perechi de tip (distanta, nod)
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
///algo lui Bellman-Ford -> calculez o distanta minima orientativa fara sa tin cont de flux
void bellman_ford()
{
///setez vectorul de distante a.i. fiecare nod sa retina o valoare maxima
memset(dist_bf, 0x3f, sizeof(dist_bf));
///setez pentru sursa distanta 0 si faptul ca se afla in coada si introduc sursa in coada
dist_bf[src] = 0;
q.push(src);
coada[src] = 1;
///cat timp am elemente in coada
while(!q.empty())
{
///preiau elementul din varful cozii si il setez ca fiind scos din coada
int x = q.front();
coada[x] = 0;
q.pop();
///iterez prin lista de adiacenta a nodului scos din coada
for(auto it: l[x])
{
///daca are capacitate pozitiva, deci mai pot trimite flux pe acolo
if(cap[x][it])
{
///verific daca gasesc o distanta mai mica decat cea curenta pentru nodul respectiv
if(dist_bf[x] + cst[x][it] < dist_bf[it])
{
///in caz afirmativ actualizez distanta
dist_bf[it] = dist_bf[x] + cst[x][it];
///daca nodul nu e in coada il introduc si ii modific statusul
if(!coada[it])
{
coada[it] = 1;
q.push(it);
}
}
}
}
}
}
///alo lui Dijkstra -> calculez distanta minima, tinand cont de distanta de la Bellman-Ford
int dijkstra()
{
///setez vectorul de distante a.i. fiecare nod sa retina o valoare maxima
memset(dist, 0x3f, sizeof(dist));
///setez pentru sursa distanta pe plus 0 si distanta reala 0
dist[src] = 0;
dist_d[src] = 0;
///introduc in coada perechea (distanta, nod) pt sursa
pq.push(make_pair(dist[src], src));
///cat timp am elemente in coada
while(!pq.empty())
{
///preiau perechea din varful cozii si memorez costul(distanta) si nodul, urmand se elimin perechea din coada
int c = pq.top().first, x = pq.top().second;
pq.pop();
///daca distanta reala a nodului este egala cu distanta pe plus scoasa din coada
if(dist[x] == c)
{
///iterez prin lista de adiacenta a nodului curent
for(auto it: l[x])
{
///daca am capacitate pozitiva pe acea muchie
if(cap[x][it] > 0)
{
///in cazul in care pot actualiza distanta pozitiva a nodului vecin atunci fac toate actualizarile necesare
if(dist[x] + cst[x][it] + dist_bf[x] - dist_bf[it] < dist[it])
{
dist[it] = dist[x] + cst[x][it] + dist_bf[x] - dist_bf[it];
dist_d[it] = dist_d[x] + cst[x][it];
///actualizez vectorul de tati -> pot reconstitui drumul
tata[it] = x;
///adaug in coada perechea (distanta reala, nod vecin)
pq.push(make_pair(dist[it], it));
}
}
}
}
}
///pun in vectorul de distante Bellman_Ford valorile vect de distnte reale
memcpy(dist_bf, dist_d, sizeof(dist));
///daca distanta destinatiei nu s-a modificat atunci intorc 0, ceea ce inseamna ca am determinat-o deja
if(dist[dest] == 0x3f3f3f3f)
return 0;
///Algo de determinare de flux maxim
///calculez cata capacitate am consumat prin parcurerea facuta si actualizez costurile
int minim = 0x3f3f3f3f;
for(int i = dest; i != src; i = tata[i])
{
int j = tata[i];
minim = min(minim, cap[j][i]);
}
for(int i = dest; i != src; i = tata[i])
{
int j = tata[i];
cap[i][j] += minim;
cap[j][i] -= minim;
}
///actualizez costul minim al fluxului maxim determinat
cost_flux += minim * dist_d[dest];
return 1;
}
int main()
{
int x, y, ct, cp, bf;
///citire
in>>n>>m>>src>>dest;
for(int i =1; i <= m; i++)
{
in>>x>>y>>cp>>ct;
l[x].push_back(y);
l[y].push_back(x);
cap[x][y] = cp;
cst[x][y] = ct;
cst[y][x] = -ct;
}
///apel Bellman-Ford -> det dist orientative
bellman_ford();
///cautam cu Dijkstra cea mai buna distanta si ne oprim cand nu mai avem ce actualiza pt distanta destinatiei
while(dijkstra());
///afisare
out<<cost_flux;
return 0;
}
///Complexitate timp: O(n*(m^2)*log n)
///Complexitate spatiu: O(n^2)