Cod sursa(job #2958831)

Utilizator mihairazvan03Dana Mihai mihairazvan03 Data 28 decembrie 2022 15:47:27
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.75 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <climits>

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>> vCost;   //costul unui arc dintre 2 noduri (0 daca nu avem muchie). Pt arcele inverse trecem costul dat cu minus
vector<int> distInit;
vector<int> dist;
vector<int> distActuala;
vector<int> p;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;


bool Dijkstra()
{
    int i, currenNode, currenNodeDist, j, newNode, newDist, capacitateMin = INT_MAX, copieDestinatie = destinatie, costActual = 0;

    for(i = 1; i <= n; i++)
        dist[i] = INT_MAX;

    dist[sursa] = 0;
    distActuala[sursa] = 0;
    pq.push(make_pair(0, sursa));

    while(!pq.empty())
    {
        currenNode = pq.top().second;
        currenNodeDist = pq.top().first;
        pq.pop();

        if(dist[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
                {
                    newDist = dist[currenNode] + vCost[currenNode][newNode] + distInit[currenNode] - distInit[newNode];

                    if (newDist < dist[newNode])
                    {
                        dist[newNode] = newDist;
                        distActuala[newNode] = distActuala[currenNode] + vCost[currenNode][newNode];
                        p[newNode] = currenNode;
                        pq.push(make_pair(dist[newNode], newNode));
                    }
                }
            }
    }

    for(i = 1; i <= n; i++)
        distInit[i] = distActuala[i];

    if(dist[destinatie] == INT_MAX)       //inseamna ca nu am reusit sa ajungem la destinatie
        return false;

    while(copieDestinatie != sursa)
    {
        capacitateMin = min(capacitateMin, vCapacitate[p[copieDestinatie]][copieDestinatie]);
        costActual += vCost[p[copieDestinatie]][copieDestinatie];
        copieDestinatie = p[copieDestinatie];
    }

    costMin += capacitateMin * distActuala[destinatie];
    copieDestinatie = destinatie;

    while(copieDestinatie != sursa)
    {
        vCapacitate[p[copieDestinatie]][copieDestinatie] -= capacitateMin;
        vCapacitate[copieDestinatie][p[copieDestinatie]] += capacitateMin;    //crestem capacitatea ramasa la arcele inverse
        copieDestinatie = p[copieDestinatie];
    }

    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++)
        distInit[i] = INT_MAX;

    distInit[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(distInit[currenNode] + vCost[currenNode][newNode] < distInit[newNode])  //e mai ieftin sa ajungem la newNode trecand prin currentNode
                {
                    distInit[newNode] = distInit[currenNode] + vCost[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);
    vCost.resize(n + 1);
    dist.resize(n + 1, 0);
    distActuala.resize(n + 1, 0);
    distInit.resize(n + 1, 0);
    p.resize(n + 1);
    for(i = 0; i <= n; i++)
    {
        vCapacitate[i].resize(n + 1, 0);
        vCost[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;
        vCost[nod1][nod2] = cost;
        vCost[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;
}