Cod sursa(job #869036)
#include <cstring>
#include <fstream>
#include <vector>
#include <queue>
using namespace std;
typedef vector<int>::iterator it;
const int MaxN = 205;
const int oo = 0x3f3f3f3f;
vector<int> G[MaxN];
int N, Cost[MaxN][MaxN], Distance[MaxN], Father[MaxN];
int Source, Sink, Capacity[MaxN][MaxN], Flow[MaxN][MaxN];
queue<int> Q;
bool InQ[MaxN];
int Solution;
void InitBF(int Start) {
memset(Distance, oo, sizeof(Distance));
memset(Father, -1, sizeof(Father));
Distance[Start] = 0, Father[Start] = Start;
Q.push(Start), InQ[Start] = true;
}
bool BellmanFord(int Start, int End) {
for (InitBF(Start); !Q.empty(); Q.pop()) {
int X = Q.front(); InQ[X] = false;
if (X == End)
continue;
for (it Y = G[X].begin(); Y != G[X].end(); ++Y) {
if (Capacity[X][*Y] > Flow[X][*Y] && Distance[X] + Cost[X][*Y] < Distance[*Y]) {
Distance[*Y] = Distance[X] + Cost[X][*Y], Father[*Y] = X;
if (!InQ[*Y])
Q.push(*Y), InQ[*Y] = true;
}
}
}
return Father[End] != -1;
}
int MaximumMatching() {
int MaxMatch = 0, MatchCost = 0;
while(BellmanFord(Source, Sink)) {
for (int X = Sink; X != Source; X = Father[X])
++Flow[Father[X]][X], --Flow[X][Father[X]];
MatchCost += Distance[Sink];
}
return MatchCost;
}
inline void AddEdge(int x, int y, int cost) {
G[x].push_back(y), G[y].push_back(x);
Cost[x][y] = cost, Cost[y][x] = -cost;
Capacity[x][y] = 1, Capacity[y][x] = 0;
}
void Read() {
ifstream in("cc.in");
in >> N;
for (int i = 1; i <= N; ++i) {
for (int j = N + 1; j <= 2 * N; ++j) {
int cost; in >> cost;
AddEdge(i, j, cost);
}
}
Source = 0, Sink = 2 * N + 1;
for (int i = 1; i <= N; ++i)
AddEdge(Source, i, 0);
for (int i = N + 1; i <= 2 * N; ++i)
AddEdge(i, Sink, 0);
in.close();
}
void Print() {
ofstream out("cc.out");
out << Solution << "\n";
out.close();
}
int main() {
Read();
Solution = MaximumMatching();
Print();
return 0;
}