Pagini recente » Istoria paginii runda/summer-challenge-2021/clasament | Cod sursa (job #544062) | Cod sursa (job #1556492) | Cod sursa (job #1173487) | Cod sursa (job #2961853)
#include <fstream>
#include <iostream>
#include <climits>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
ifstream fin("fmcm.in");
ofstream fout("fmcm.out");
struct edge{
int node;
int capacity;
int flow;
int cost;
int new_cost;
};
vector<edge> ad[355];
int n, m, s, d; // nr noduri, nr muchii, sursa, destinatie
int x, y, c, z;
int new_costs[355], father[355];
queue<int> q;
priority_queue <pair<int, int>> pq; // pair(-costul minim pana la nod, nodul)
vector<int> path;
void bellmanFord() {
for(int i = 1; i <= n; i ++)
new_costs[i] = INT_MAX;
new_costs[s] = 0;
q.push(s);
while(!q.empty()) {
int node = q.front();
q.pop();
for(auto vec : ad[node]) {
if(new_costs[vec.node] > new_costs[node] + vec.cost){
new_costs[vec.node] = new_costs[node] + vec.cost;
q.push(vec.node);
}
}
}
}
int dijkstra() {
// initializari
for(int i = 1; i <= n; i ++) {
new_costs[i] = INT_MAX;
father[i] = 0;
}
new_costs[s] = 0;
pq.push(make_pair(0, s));
while(!pq.empty()) {
int node = pq.top().second;
pq.pop();
for(auto vec : ad[node]) {
if((new_costs[vec.node] > new_costs[node] + vec.new_cost) && (vec.flow < vec.capacity)) {
new_costs[vec.node] = new_costs[node] + vec.new_cost;
father[vec.node] = node;
pq.push(make_pair(-new_costs[vec.node], vec.node));
}
}
}
if(new_costs[d] != INT_MAX)
return 1;
else
return 0;
}
int findPosition(int node, int vec){
for(int i = 0; i < ad[node].size(); i ++)
if(ad[node][i].node == vec)
return i;
return -1;
};
int main() {
fin >> n >> m >> s >> d;
for(int i = 1; i <= m; i ++) {
fin >> x >> y >> c >> z;
ad[x].push_back({y, c,0, z, z});
}
// calculeaza costurile posibil negative de la sursa la destinatie folosind Bellman-Ford
bellmanFord();
// adaug la fiecare muchie un nou cost => new_cost = cost + new_costs[x] - new_costs[y]
for(int i = 1; i <= n; i ++)
for(int j = 0; j < ad[i].size(); j ++) {
ad[i][j].new_cost = ad[i][j].cost + new_costs[i] - new_costs[ad[i][j].node];
}
// adaug muchiile inverse de de capacity = 0 si flow = 0
for(int i = 1; i <= n; i ++)
for(int j = 0; j < ad[i].size(); j ++)
if(ad[i][j].capacity != 0) {
ad[ad[i][j].node].push_back({i, 0, 0, -ad[i][j].cost, -ad[i][j].new_cost});
}
// flux cu Dijkstra
while(dijkstra()) {
int sth = d;
path.clear();
// pun drumul gasit in vectorul path
while(father[sth] != 0) {
path.push_back(father[sth]);
sth = father[sth];
}
// calculez fluxul maxim pe acest drum
int max_flow = INT_MAX;
sth = d;
while (father[sth] != 0) {
int pos = findPosition(father[sth], sth);
max_flow = min(max_flow, ad[father[sth]][pos].capacity - ad[father[sth]][pos].flow);
sth = father[sth];
}
// adun fluxul pe fiecare muchie; scad fluxul pe muchiile inverse
sth = d;
while (father[sth] != 0) {
int pos1 = findPosition(father[sth], sth);
ad[father[sth]][pos1].flow += max_flow;
int pos2 = findPosition(sth, father[sth]);
ad[sth][pos2].flow -= max_flow;
sth = father[sth];
}
}
int result = 0;
for(int i = 1; i <= n; i ++) {
for(auto v : ad[i]) {
if(v.flow > 0)
result = result + v.flow * v.cost;
}
}
fout << result << '\n';
return 0;
}