#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <bitset>
#include <cstring>
#include <cassert>
#define MAXN 355
#define INF 0x3f3f3f3f
#define minimum(a,b) \
({ \
typeof(a) _a = a; \
typeof(b) _b = b; \
_a<=_b?_a:_b; \
})
using namespace std;
typedef unsigned short uint16;
class CHeap
{
private:
uint16 size;
vector<uint16> vIndexes;
vector<pair<int,uint16> > vHeap;
inline void swap(const uint16 first, const uint16 second)
{
vIndexes[vHeap[first].second]=second;
vIndexes[vHeap[second].second]=first;
pair<int,uint16> aux;
aux=vHeap[first];
vHeap[first]=vHeap[second];
vHeap[second]=aux;
}
void siftUp(int index)
{
int parent=(index-1-!(index%2))>>1;
while(parent>=0 && vHeap[index].first<vHeap[parent].first)
{
swap(parent,index);
index=parent;
parent=(index-1-!(index%2))>>1;
}
}
void siftDown(int index)
{
int child1,child2;
bool ord=true;
child1=(index<<1)+1;
child2=(index+1)<<1;
while(ord && child1<size)
{
ord=false;
if(child2<size)
{
if(vHeap[child1].first<vHeap[child2].first)
{
if(vHeap[child1]<vHeap[index])
{
swap(child1,index);
index=child1;
ord=true;
}
}
else if(vHeap[child2].first<vHeap[index].first)
{
swap(child2,index);
index=child2;
ord=true;
}
}
else if(vHeap[child1].first<vHeap[index].first)
{
swap(child1,index);
index=child1;
ord=true;
}
child1=(index<<1)+1;
child2=(index+1)<<1;
}
}
public:
CHeap() : size(0)
{}
void insert(const pair<int,uint16>& val)
{
vHeap.push_back(val);
vIndexes.push_back(size++);
siftUp(size-1);
}
inline void modify(const int pos, const pair<int,uint16>& val)
{
vHeap[pos]=val;
siftUp(pos);
}
inline void remove(const int pos)
{
swap(pos,--size);
vHeap.pop_back();
siftDown(pos);
}
inline const pair<int,uint16>& getElement(const int pos) const
{
return vHeap[pos];
}
inline int getPos(const int index) const
{
return vIndexes[index];
}
inline bool empty() const
{
return (size==0);
}
void print()
{
for(unsigned int i=0; i<vHeap.size(); ++i)
{
cout<<"("<<vHeap[i].first<<" "<<vHeap[i].second+1<<") ";
}
cout<<endl;
for(unsigned int i=0; i<vIndexes.size(); ++i)
{
cout<<"("<< vIndexes[i] <<") ";
}
cout<<endl;
}
};
struct Edge
{
Edge() :
node(0),
cost(0)
{}
Edge(const short n, const short c) :
node(n),
cost(c)
{}
short node;
short cost;
};
typedef vector<vector<Edge> > Graph;
bool BellmanFord(const Graph &graph,
int **capacity,
int **flow,
const int n,
const uint16 s,
int *dist // out
)
{
queue<uint16> Q;
uint16 count[MAXN]={0};
bool neg_cycle=false;
bitset<MAXN> inQ;
memset(dist,0x3f,n*sizeof(int));
dist[s]=0;
Q.push(s);
inQ[s]=true;
while(!Q.empty() && !neg_cycle)
//for (int i=0; i<n; ++i)
{
int node=Q.front();
Q.pop();
inQ[node]=false;
//bool stop = true;
//for (node=0; node<n; ++node)
for (int j=0; j<graph[node].size(); ++j)
{
if (capacity[node][graph[node][j].node] - flow[node][graph[node][j].node] > 0
&& dist[node] + graph[node][j].cost < dist[graph[node][j].node])
{
dist[graph[node][j].node] = dist[node] + graph[node][j].cost;
if(!inQ[graph[node][j].node])
{
if(count[graph[node][j].node]>n)
{
neg_cycle=true;
}
else
{
Q.push(graph[node][j].node);
inQ[graph[node][j].node]=true;
count[graph[node][j].node]++;
}
}
//stop = false;
}
}
//if (stop)
// break;
}
return neg_cycle;
}
int Dijkstra
(
Graph& graph,
int **capacity,
int **flow,
const int n,
const uint16 src,
const uint16 dest,
int *dist,
int &incDist,
int &minFlow
)
{
CHeap heap;
short pred[n];
for (int i=0; i<n; ++i)
{
for (int j=0; j<graph[i].size(); ++j)
{
if (dist[i] != INF && dist[graph[i][j].node] != INF)
graph[i][j].cost = graph[i][j].cost + dist[i] - dist[graph[i][j].node];
}
}
/*for (int i = 0; i < n; i++)
cout << dist[i] << " ";
cout << endl << endl;*/
/*for (int i=0; i<n; ++i)
{
cout << i+1 << "-> ";
for (int j=0; j<graph[i].size(); ++j)
{
cout << "(" << graph[i][j].node+1 << "," << graph[i][j].cost << ") ";
}
cout << "\n";
}*/
for(int i=0; i<n; ++i)
{
heap.insert(make_pair(INF,i));
dist[i] = INF;
}
heap.modify(heap.getPos(src), make_pair(0,src));
dist[src] = 0;
//cout << "dist[dest] = " << dist[dest] << endl;
/*cout << "Initial heap\n";
heap.print();
cout << endl;*/
while (!heap.empty())
{
const pair<int,uint16> node=heap.getElement(0);
heap.remove(0);
//cout << "Popped " << node.second+1 << endl;
if (node.first==INF)
{
//cout << "Fail\n";
break;
}
//dist[node.second] = node.first;
for (vector<Edge>::iterator it=graph[node.second].begin(); it!=graph[node.second].end(); ++it)
{
const int alt = dist[node.second] + it->cost;
if (capacity[node.second][it->node] - flow[node.second][it->node] > 0)
{
//cout << node.second+1 << "->" << it->node+1 << endl;
assert(it->cost>=0);
}
if (alt<dist[it->node] &&
capacity[node.second][it->node] - flow[node.second][it->node] > 0)
{
dist[it->node] = alt;
//heap.print();
//cout << "Modifying " << it->node+1 << " with " << dist[it->node] << endl;
heap.modify(heap.getPos(it->node),make_pair(alt,it->node));
//heap.print();
pred[it->node] = node.second;
}
}
}
//cout << "Ended\n";
if (dist[dest] != INF)
{
minFlow = INF;
for (int i=dest; i!=src; i=pred[i])
{
//cout << i+1 << "->";
minFlow = minimum(minFlow, capacity[pred[i]][i] - flow[pred[i]][i]);
}
//cout << src+1 << endl;
for (int i=dest; i!=src; i=pred[i])
{
flow[pred[i]][i] += minFlow;
flow[i][pred[i]] -= minFlow;
}
/*cout << "dist[dest] = " << dist[dest] << endl;
cout << "Current sum = " << incDist << endl;
cout << "Current flow = " << minFlow << endl;
cout << endl << endl;*/
incDist += dist[dest];
minFlow *= incDist;
return true;
}
return false;
}
int EdmondsKarp
(
Graph& graph,
int **capacity,
int **flow,
const int n,
const uint16 src,
const uint16 dest,
int *dist,
int incDist
)
{
int minFlow=0, curFlow;
while (Dijkstra(graph, capacity, flow, n, src, dest, dist, incDist, curFlow))
{
minFlow += curFlow;
//cout << "Current min flow = " << minFlow << endl;
}
return minFlow;
}
int main()
{
int n,m;
uint16 s,d;
int **capacity, **flow, *dist;
Graph graph;
fstream fin("fmcm.in", fstream::in);
fstream fout("fmcm.out", fstream::out);
fin >> n >> m >> s >> d;
//cout << n << " " << m << " " << s << " " << d << endl;
// do allocations for memory
graph.resize(n);
capacity = new int*[n];
flow = new int*[n];
dist = new int[n+1];
for (int i=0; i<n; ++i)
{
capacity[i] = new int[n];
memset(capacity[i], 0, sizeof(int)*n);
flow[i] = new int[n];
memset(flow[i], 0, sizeof(int)*n);
}
// read our graph from the file
for (int i=0; i<m; ++i)
{
int x, y, c, z;
fin >> x >> y >> c >> z;
graph[x-1].push_back(Edge(y-1, z));
graph[y-1].push_back(Edge(x-1, -z));
capacity[x-1][y-1] = c;
}
/*for (int i=0; i<n; ++i)
{
cout << i+1 << "-> ";
for (int j=0; j<graph[i].size(); ++j)
{
cout << "(" << graph[i][j].node+1 << "," << graph[i][j].cost << ") ";
}
cout << "\n";
}
//Sum = -6
cout << "\n";*/
BellmanFord(graph, capacity, flow, n, s-1, dist);
//out << dist[d-1] << "\n";
const int incDist = dist[d-1];
fout << EdmondsKarp(graph, capacity, flow, n, s-1, d-1, dist, incDist) << endl;
fin.close();
fout.close();
return 0;
}