Pagini recente » Cod sursa (job #807232) | Cod sursa (job #1556219) | Cod sursa (job #2728538) | Cod sursa (job #1881855) | Cod sursa (job #2958839)
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <climits>
//facem ca la problema cu flux doar ca adaugam niste modificari. pt fiecare arc, pe langa capacitate retinem si costul, iar pt arcele inverse retinem costul cu minus si capacitate 0. Incercam
//cat timp se mai poate adauga flux, si de fiecare data incercam pt capacitatea respectiva maxima de flux sa gasim un drum de cost minim. Folosim Bellman Ford pt a calcula vCost, adica costul
//minim de la sursa la un nod (facem cu bellman pt ca avem si costuri negative). Apoi pentru a putea aplica dijkstra trebuia sa facem aceste costuri pozitive, asa ca pt fiecare arc dintre 2 noduro
//nod1 si nod2 vCost[arc] = vCostArc[nod1][nod2] + vCost[nod1] - vCost[nod2]
//Complexitatea de timp O(n * (m ^2) * log n), unde n = nr noduri, m = nr arce. Complex spatiu O(n ^ 2)
using namespace std;
ifstream in("fmcm.in");
ofstream out("fmcm.out");
int n, m, sursa, destinatie, costMin;
vector<vector<int>> adj;
vector<vector<int>> vCapacitate; //matricea de capacitati (ce flux avem intre 2 noduri)
vector<vector<int>> vCostArc; //costul unui arc dintre 2 noduri (0 daca nu avem muchie). Pt arcele inverse trecem costul dat cu minus
vector<int> vCostInit;
vector<int> vCost; //costul minim la la sursa la nodul respectiv
vector<int> vCostActual;
bool Dijkstra()
{
int i, currenNode, currenNodeDist, j, newNode, newCost, capacitateMin = INT_MAX, newDest = destinatie, costActual = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
vector<int> dad; //folosim pt a retine drumul care se formeaza. Incepem de la destinatie dupa mergem la dad, care e nodul de dinainte dest, si tot asa pana ajungem la sursa
dad.clear(); //trb sa stergem ce era in dijkstrau trecut. daca am da doar resize elementele s-ar pastra, nu s-ar reseta
dad.resize(n + 1);
for(i = 1; i <= n; i++)
vCost[i] = INT_MAX;
vCost[sursa] = 0;
vCostActual[sursa] = 0;
pq.push(make_pair(0, sursa));
while(!pq.empty())
{
currenNode = pq.top().second;
currenNodeDist = pq.top().first;
pq.pop();
if(vCost[currenNode] == currenNodeDist)
for(j = 0; j < adj[currenNode].size(); j++)
{
newNode = adj[currenNode][j];
if(vCapacitate[currenNode][newNode] > 0) //mai avem capacitate de flux ramasa
{
newCost = vCost[currenNode] + vCostArc[currenNode][newNode] + vCostInit[currenNode] - vCostInit[newNode];
if (newCost < vCost[newNode])
{
vCost[newNode] = newCost;
vCostActual[newNode] = vCostActual[currenNode] + vCostArc[currenNode][newNode];
dad[newNode] = currenNode;
pq.push(make_pair(vCost[newNode], newNode));
}
}
}
}
for(i = 1; i <= n; i++)
vCostInit[i] = vCostActual[i];
if(vCost[destinatie] == INT_MAX) //inseamna ca nu am reusit sa ajungem la destinatie
return false;
while(newDest != sursa)
{
capacitateMin = min(capacitateMin, vCapacitate[dad[newDest]][newDest]);
costActual += vCostArc[dad[newDest]][newDest];
newDest = dad[newDest];
}
costMin += capacitateMin * vCostActual[destinatie];
newDest = destinatie;
while(newDest != sursa)
{
vCapacitate[dad[newDest]][newDest] -= capacitateMin;
vCapacitate[newDest][dad[newDest]] += capacitateMin; //crestem capacitatea ramasa la arcele inverse
newDest = dad[newDest];
}
return true;
}
void BellmanFord()
{
int i, currenNode, j, newNode;
queue<int> coada;
vector<int> inCoada(n + 1, 0); //daca nodul se afla in coada
for(i = 1; i <= n; i++)
vCostInit[i] = INT_MAX;
vCostInit[sursa] = 0;
coada.push(sursa);
inCoada[sursa] = 1;
while (!coada.empty())
{
currenNode = coada.front();
coada.pop();
inCoada[currenNode] = 0; //nodul nu mai e in coada pt ca i-am dat pop
for(j = 0; j < adj[currenNode].size(); j++)
{
newNode = adj[currenNode][j];
if(vCapacitate[currenNode][newNode])
if(vCostInit[currenNode] + vCostArc[currenNode][newNode] < vCostInit[newNode]) //e mai ieftin sa ajungem la newNode trecand prin currentNode
{
vCostInit[newNode] = vCostInit[currenNode] + vCostArc[currenNode][newNode];
if (inCoada[newNode] == 0) //daca nu e deja in coada il bagam
{
inCoada[newNode] = 1;
coada.push(newNode);
}
}
}
}
}
int main()
{
int i, nod1, nod2, capacitate, cost;
in >> n >> m >> sursa >> destinatie;
adj.resize(n + 1);
vCapacitate.resize(n + 1);
vCostArc.resize(n + 1);
vCost.resize(n + 1, 0);
vCostActual.resize(n + 1, 0);
vCostInit.resize(n + 1, 0);
for(i = 0; i <= n; i++)
{
vCapacitate[i].resize(n + 1, 0);
vCostArc[i].resize(n + 1, 0);
}
for (int i = 0; i < m; i++)
{
in >> nod1 >> nod2 >> capacitate >> cost;
adj[nod1].push_back(nod2);
adj[nod2].push_back(nod1);
vCapacitate[nod1][nod2] = capacitate;
vCostArc[nod1][nod2] = cost;
vCostArc[nod2][nod1] = -cost; //costul pt arcul invers este minusul costului arcului
}
BellmanFord();
for(;;) //facem dijkstra cat se poate
if(Dijkstra() == false)
break;
out << costMin;
return 0;
}