Pagini recente » Cod sursa (job #2836179) | Cod sursa (job #1107352) | Cod sursa (job #785806) | Cod sursa (job #3255172) | Cod sursa (job #2967291)
// Flux maxim de cost minim
// Complexitate O(N*M^2*logN)
#include <bits/stdc++.h>
using namespace std;
ifstream f("fmcm.in");
ofstream g("fmcm.out");
int n, s, d, capacitate[351][351], cost[351][351], inQ[351], distVeche[351], dist[351], distNoua[351], parinte[351], raspuns;
vector<int> muchii[351];
queue<int>q;
priority_queue<pair<int, int> > pq; //desc
bool dijkstra() {
// Initial niciun nod nu e vizitat
for(int i = 0; i <= n; ++i)
dist[i] = 1000000000;
// Nodul sursa e vizitat si se afla la distanta 0
dist[s] = 0;
distNoua[s] = 0;
pq.push({0, s});
// Cat timp mai am elemente
while(!pq.empty()) {
int c = -pq.top().first;
int nod = pq.top().second;
pq.pop();
// Daca am trecut deja prin nod continuam
if(dist[nod] != c) {
continue;
}
// Verific pentru toti vecinii daca pot forma un drum mai bun din nodul curent
for(auto it : muchii[nod])
// Daca am capacitate pe muchie
if(capacitate[nod][it]) {
int d = c + cost[nod][it];
// Adaugam distVeche[nod] - distVeche[it] pentru a face costul pozitiv
d += distVeche[nod] - distVeche[it];
if(d < dist[it])
{
// In dist pastrez costul modificat care e numai pozitiv
dist[it] = d;
// In distNoua pastrez costul adevarat al drumului care poate fi si negativ
distNoua[it] = distNoua[nod] + cost[nod][it];
// Momentan cel mai bun drum pana la vecin este prin nod
parinte[it] = nod;
// Adaug in coada vecinul si costul drumului pana la el
pq.push({-dist[it], it});
}
}
}
// Distanta veche pentru pasul urmator e acum distanta noua
for(int i = 1; i <= n; ++i) {
distVeche[i] = distNoua[i];
}
// Daca nu am ajuns la destinatie ma opresc
if(dist[d] == 1000000000)
return false;
// Calculez fluxul pe care pot sa-l adaug pe drumul minim si costul
int flux = 1000000000, rasp = 0;
int nod = d;
while(nod != s) {
int p = parinte[nod];
flux = min(flux, capacitate[p][nod]);
rasp += cost[p][nod];
nod = p;
}
// Adaug la raspuns costul fluxului adaugat
raspuns += rasp * flux;
// Adaug fluxul pe drumul gasit
nod = d;
while(nod != s) {
int p = parinte[nod];
capacitate[p][nod] -= flux;
capacitate[nod][p] += flux;
nod = p;
}
// Am gasit un drum pe care pot adauga flux
return true;
}
// Calculez distanta minima de la sursa la toate nodurile
void bellmandFord() {
for(int i = 0; i <= n; ++i)
distVeche[i] = 1000000000;
q.push(s);
inQ[s] = 1;
distVeche[s] = 0;
while(!q.empty()) {
int nod = q.front();
inQ[nod] = 0;
q.pop();
for(auto vecin : muchii[nod])
if(capacitate[nod][vecin] && distVeche[nod] + cost[nod][vecin] < distVeche[vecin]) {
distVeche[vecin] = distVeche[nod] + cost[nod][vecin];
if(!inQ[vecin]) {
q.push(vecin);
inQ[vecin] = 1;
}
}
}
}
int main()
{
int m;
f >> n >> m >> s >> d;
while(m--) {
int x, y, c, z;
f >> x >> y >> c >> z;
muchii[x].push_back(y);
muchii[y].push_back(x);
capacitate[x][y] = c;
cost[x][y] = z;
cost[y][x] = -z;
}
bellmandFord();
while(dijkstra());
g << raspuns;
g.close();
f.close();
return 0;
}