Pagini recente » Cod sursa (job #685951) | Cod sursa (job #2364939) | Cod sursa (job #1056508) | Cod sursa (job #1057554) | Cod sursa (job #2959560)
#include <iostream>
#include <fstream>
#include <queue>
#include <vector>
#define MAX_SIZE 200
using namespace std;
int L, R, nrNoduri, x, y;
vector<int> adjList[MAX_SIZE];
// Matrice ce retine capacitatea maxima pentru fiecare muchie in parte
int C[MAX_SIZE + 1][MAX_SIZE + 1];
// Matrice ce retine fluxul curent pentru fiecare muchie in parte
int F[MAX_SIZE + 1][MAX_SIZE + 1];
int D_Extern[MAX_SIZE + 1];
int D_Intern[MAX_SIZE + 1];
vector<pair<int, int>> drumuri = vector<pair<int, int>>();
int main() {
ifstream fin("harta.in");
ofstream fout("harta.out");
// Se citesc cardinanul multimii L, resp cardinalul multimii R si numarul de muchii
// Se citeste N, numarul de noduri
fin >> nrNoduri;
L = nrNoduri;
R = nrNoduri;
// Trebuie sa adaugam un nod sursa pe care sa il legam de toate nodurile din L (pt ca nodurile din L incep de la 1, sursa va fi 0)
int S = 0;
// Trebuie sa adaugam un nod destinatie pe care sa il legam de toate nodurile din R (cum nodurile din L si R sunt in numar de L + R si sunt indexate de la 1, trebuie sa punem destinatia pe pozitia L + R + 1)
int D = L + R + 1;
// Se citesc gradele (extern respectiv intern)
for(int i = 1; i <= nrNoduri; ++i) {
fin >> x >> y;
D_Extern[i] = x;
D_Intern[i] = y;
// Adaugam muchie intre sursa si fiecare nod, care va avea capacitatea egala cu gradul de iesire
adjList[0].push_back(i);
// Adaugam si muchia inversa, graf rezidual
adjList[i].push_back(0);
C[0][i] = x;
// Adaugam muchie intre fiecare nod si destinatie, care va avea capacitatea egala cu gradul de intrare
adjList[i+L].push_back(D);
C[i+L][D] = y;
// Adaugam si muchia inversa, graf rezidual
adjList[D].push_back(i+L);
}
// Trebuie sa adaugam muchie de capacitate 1 intre nodurile din L si cele din R
for(int i = 1; i <= nrNoduri; i++) {
for(int j = 1; j <= nrNoduri; j++) {
if(i==j) {
continue;
}
adjList[i].push_back(j+L);
// Adaugam si muchia inversa, graf rezidual
adjList[j+L].push_back(i);
C[i][j+L] = 1;
}
}
//cout << "Destinatia este " << D << "\n";
// Daca am gasit sau nu un path de ameliorare, ne ajuta sa stim cand ne oprin din a face BFS pe graful rezidual
bool augumentationPathFound = false;
// Coada ce va fi folosita pentru parcurgerea BF
queue<int> q;
// Vector ce va retine daca un nod este vizitat sau nu in cadrul parcurgerii
vector<bool> visited;
// Vectorul de tati al arborelui generat de BFS
vector<int> parent;
// Daca am ajuns la nodul destinatie in BFS
bool destinationReched;
// Variabila ce va retine la final flow-ul maxim si va reprezenta suma flow-urilor de pe toate drumurile de ameliorare gasite
int totalFlow = 0;
do {
// Pentru fiecare iteratie a BFS-ului trebuie sa resetam coada, vectorul visited, vectorul de tati si destinationReached
q = queue<int>();
visited = vector<bool>(L+R+1, false);
parent = vector<int>(L+R+1, -1);
destinationReched = false;
// Incepem prin a introduce in coada nodul de start
q.push(S);
// Cat timp coada nu este vida
while(!q.empty() && !destinationReched) {
// Scoatem cel mai vechi nod din coada si il marcam ca si vizitat
auto currentNode = q.front();
q.pop();
visited[currentNode] = true;
// Trecem prin fiecare dintre nodurile vecine cu nodul curent
for(int j = 0; j < adjList[currentNode].size(); j++) {
auto currentNeighbor = adjList[currentNode][j];
// Daca vecinul nu a fost inca vizitat si catre el capacitatea reziduala este mai mare decat 0 (capacitate - flux), atunci adaugam nodul in coada
if(!visited[currentNeighbor] && C[currentNode][currentNeighbor] - F[currentNode][currentNeighbor] > 0) {
q.push(currentNeighbor);
// Marcam si nodul vecin ca fiind vizitat
visited[currentNeighbor] = true;
// Actualizam parintele nodului vecin (care este nodul curent)
parent[currentNeighbor] = currentNode;
// Daca am ajuns cumva la nodul destinatie, atunci oprim BFS-ul
if(currentNeighbor == D) {
destinationReched = true;
break;
}
}
}
}
if(destinationReched) {
// cout << "S-a gasit un path de ameliorare vectorul de tati este: ";
// for(auto x: parent) {
// cout << x << " ";
// }
//cout << " , iar muchiile ce compun path-ul sunt: ";
// Daca am gasit un drum de ameliorare, atunci trebuie sa il reconstruim din vectorul de tati si sa actualizam fluxul muchiilor ce fac parte din acel drum
int cNode = D;
int pNode = D;
int bottleneck = -1;
bool edgeFound = false;
pair<int, int> cPair = pair<int, int>();
while(true) {
if(pNode == -1) {
break;
}
if(pNode != -1 && pNode != cNode) {
// Daca parent node-ul este egal cu 0, inseamna ca cNode (nodul curent) face parte din multimea L.
cout << "(" << pNode << " " << cNode << ") ";
if(pNode == 0) {
cPair.first = cNode;
}
// Daca curent node-ul este egal cu destinatia (L+R+1), atunci inseamna ca pNode (parent node-ul) face parte din multimea R
if(cNode == L + R + 1) {
cPair.second = pNode - L;
}
if(bottleneck == -1 || C[pNode][cNode] - F[pNode][cNode] < bottleneck) {
bottleneck = C[pNode][cNode] - F[pNode][cNode];
}
}
cNode = pNode;
pNode = parent[pNode];
}
printf("[%d %d] ", cPair.first, cPair.second);
cout << "Pt path-ul de mai sus fluxul maxim pe care il putem adauga este egal cu " << bottleneck << "\n";
cNode = D;
pNode = D;
while(true) {
if(pNode == -1) {
break;
}
if(pNode != -1 && pNode != cNode) {
// Scadem bottleneck-ul din muchia din graful initial si adaugam la muchia inversa bottleneck-ul cu semn schimbat
F[pNode][cNode] += bottleneck;
F[cNode][pNode] -= bottleneck;
}
cNode = pNode;
pNode = parent[pNode];
}
totalFlow += bottleneck;
cout << "\n";
augumentationPathFound = true;
} else {
augumentationPathFound = false;
}
} while(augumentationPathFound);
//cout << "Flow-ul maxim este " << totalFlow;
fout << totalFlow << "\n";
cout << "==============================";
for(int i = 1; i <= L; i++) {
for(int j = L+1; j <= L + R; j++) {
if(F[i][j] == C[i][j] && F[i][j] == 1) {
fout << i << " "<< j - L << "\n";
}
}
}
return 0;
}