-
Notifications
You must be signed in to change notification settings - Fork 249
/
Copy pathMinCostFB.cpp
135 lines (113 loc) · 3.4 KB
/
MinCostFB.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/************************************************************************************
Min Cost Flow (or Min Cost Max Flow) algorithm with
Ford-Bellman algorithm as shortest path search method.
Works O(N ^ 6). Less on practice.
Runs in O(N ^ 4) for bipartite matching case.
Based on problem 394 from informatics.mccme.ru
http://informatics.mccme.ru//mod/statements/view3.php?chapterid=394
************************************************************************************/
#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <cassert>
#include <utility>
#include <iomanip>
using namespace std;
const int MAXN = 1050;
const long long INF = (long long) 1e15;
struct edge {
int from, to;
int flow, cap;
long long cost;
};
int n;
int cost[MAXN][MAXN];
vector <edge> e;
long long dist[MAXN];
int par[MAXN];
int edge_num;
int s = 0, t = MAXN - 1;
long long minCost(int flow) {
long long result = 0;
while (true) {
for (int i = s; i <= t; i++)
dist[i] = INF;
dist[s] = 0;
while (true) {
bool change = false;
for (int i = 0; i < edge_num; i++) {
int from = e[i].from, to = e[i].to;
if (e[i].flow == e[i].cap)
continue;
if (dist[from] == INF)
continue;
if (dist[to] > dist[from] + e[i].cost) {
dist[to] = dist[from] + e[i].cost;
par[to] = i;
change = true;
}
}
if (!change)
break;
}
if (dist[t] == INF)
return result;
int push = flow;
int cur = t;
while (cur != s) {
edge tmp = e[par[cur]];
int from = tmp.from, can_push = tmp.cap - tmp.flow;
push = min(push, can_push);
cur = from;
}
flow -= push;
cur = t;
while (cur != s) {
edge tmp = e[par[cur]];
int from = tmp.from;
e[par[cur]].flow += push;
e[par[cur] ^ 1].flow -= push;
result += 1ll * push * tmp.cost;
cur = from;
}
if (flow == 0)
break;
}
return result;
}
void addEdge(int from, int to, int cap, long long cost) {
edge tmp;
tmp.from = from; tmp.to = to; tmp.flow = 0; tmp.cap = cap; tmp.cost = cost;
e.push_back(tmp);
tmp.from = to; tmp.to = from; tmp.flow = cap; tmp.cap = cap; tmp.cost = -cost;
e.push_back(tmp);
edge_num += 2;
}
int main() {
//assert(freopen("input.txt","r",stdin));
//assert(freopen("output.txt","w",stdout));
scanf("%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &cost[i][j]);
t = 2 * n + 1;
for (int i = 1; i <= n; i++)
addEdge(s, i, 1, 0);
for (int i = n + 1; i <= 2 * n; i++)
addEdge(i, t, 1, 0);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
addEdge(i, n + j, 1, cost[i][j]);
cout << minCost(n) << endl;
return 0;
}