Pagini recente » Cod sursa (job #2254185) | Cod sursa (job #565009) | Cod sursa (job #213303) | Cod sursa (job #1129126) | Cod sursa (job #2085520)
#include <queue>
#include <vector>
#include <climits>
#include <iostream>
#include <fstream>
#include <bitset>
using namespace std;
ifstream in("fmcm.in");
ofstream out("fmcm.out");
int const nmax = 350;
struct Edge{
int to;
int rev;
int cost;
int cap;
int flow;
};
vector<Edge> g[1 + nmax];
int n, m, src, dest;
int dist[1 + nmax], dist2[1 + nmax];
void addedge(int a, int b, int cap, int cost) {
g[a].push_back({b, g[b].size(), cost, cap, 0});
g[b].push_back({a, g[a].size() - 1, -cost, 0, 0});
}
void bellmanford(){ //pentru O(m*n) trebuie sa faci optimizare cu vector de vizitat
for(int i = 1 ; i <= n ;i++){
dist[i] = INT_MAX;
}
dist[src] = 0;
queue<int> q;
q.push(src);
while(0 < q.size()) {
int from = q.front();
q.pop();
for(int i = 0; i < g[from].size(); i++) {
Edge &e = g[from][i];
if(e.flow < e.cap) { //mare, mare atentie
if(dist[from] + e.cost < dist[e.to]) {
dist[e.to] = dist[from] + e.cost;
q.push(e.to);
}
}
}
}
}
//Ca sa updatezi toate muchiile, ai nevoie de O(m) pasi
//dar, costul nou al muchiei depinde de costul vechi plus o expresie care depinde de starile nodurilor cost_nou - cost_vechi + dist[nod1] - dist[nod2]
//Deci daca suntem destepti si mutam update-ul de la muchii la starile modurilor, atunci update-ul se face in O(n) pasi
//Adica nu mai updatez explicit costurile muchiilor, le updatez implicit!!
//am nevoie de costurile muchiilor in Dijkstra, deci doar in Dijkstra trebuie sa-mi aduc aminte sa updatezu cu dist[nod1] - dist[nod2]
//facem acum implementarea implicita si-ti ramane tie ca tema sa faci implementarea explicita.
struct Node {
int node;
int cost;
bool operator > (Node a) const {
return (cost > a.cost);
}
};
//primeste dist si returneaza dist2
//detaliu de implementare: dupa dijkstra trebuie sa augmentam
//daca presaram niste sare in timpul lui dijkstra, nu trebuie sa mai facem DFS
//De ce aici putem presara niste sare si la Dinic nu?
//La Dinic avem blocking flow (ami multe drumuri de augmentare)
//pe cand aici dupa fiecare drum de augmentare, trebuie recalculat dist-ul
//si atunci daca tot gasim decat un singur drum cu dijkstra, dar hai punem sa punem sare
int prevnode[1 + nmax], prevedge[1 + nmax], augment[1 + nmax];
bitset<1 + nmax> vis; //vis = 0, se initializeaza usor
void dijkstra() {
vis = 0;
for(int i = 1; i <= n ;i++){
dist2[i] = INT_MAX;
}
priority_queue<Node, vector<Node> , greater<Node> > pq;
dist2[src] = 0;
augment[src] = INT_MAX;
pq.push({src , dist2[src]});
while(0 < pq.size()){
int from = pq.top().node;
pq.pop();
if(vis[from] == 0) {
vis[from] = 1;
for(int i = 0; i < g[from].size(); i++) {
Edge &e = g[from][i];
if(e.flow < e.cap) { //daca muchia e saturata, nici nu discuti
int newdist = dist2[from] + (e.cost + dist[from] - dist[e.to]); //cost modif.
if(newdist < dist2[e.to]){
dist2[e.to] = newdist;
pq.push({e.to, newdist});
prevnode[e.to] = from;
prevedge[e.to] = i;
augment[e.to] = min(augment[from], e.cap - e.flow);
}
}
}
}
}
}
//tot algoritmul de fmcm
void fmcm(int &flow, int &flowcost) {
bellmanford();
flow = flowcost = 0;
int t = 0;
while(dist[dest] < INT_MAX && dist2[dest] < INT_MAX) {
dijkstra();
if(dist2[dest] < INT_MAX) {
flow += augment[dest];
int x = dest;
while(x != src){
Edge &e = g[prevnode[x]][prevedge[x]];
e.flow += augment[dest];
g[prevnode[x]][e.rev].flow -= augment[dest];
flowcost += e.cost * augment[dest];
x = prevnode[x];
}
for(int i = 1 ; i <= n ;i++){
dist[i] += dist2[i];
}
}
}
}
int main() {
in >> n >> m >> src >> dest;
for(int i = 1 ; i <= m ;i++) {
int x, y, cap, c;
in >> x >> y >> cap >> c;
addedge(x, y, cap, c);
}
int flow, flowcost;
fmcm(flow , flowcost);
out << flowcost;
return 0;
}