Getting Confidence (MCMF)
MCMF经典题,将行列聚成点建图,由于计算的是连乘积,用取对数的方法把乘法变成加法作为流量建图计算
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x7fffffff;
const int maxn = 1e5 + 50;
const double INFF = 1.0 * 1e18;
struct MEdge {
int from, to, cap;
double cost;
MEdge(int from, int to, int cap, double cost)
: from(from), to(to), cap(cap), cost(cost) {}
};
struct MCMF { // qdd tql
int n, s, t, flow;
double cost;
vector<MEdge> es;
vector<vector<int>> G;
vector<double> d;
vector<int> p, a; // dis, prev, add
deque<bool> in;
MCMF(int n, int s, int t)
: n(n), s(s), t(t), flow(0), cost(0.0), G(n + 1), p(n + 1), a(n + 1) {}
void add_edge(int u, int v, int cap, double cost) {
G[u].push_back(es.size());
es.emplace_back(u, v, cap, cost);
G[v].push_back(es.size());
es.emplace_back(v, u, 0, -cost);
}
bool spfa() {
d.assign(n + 1, INFF);
in.assign(n + 1, false);
d[s] = 0;
in[s] = 1;
a[s] = INF;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
in[u] = false;
for (int &i : G[u]) {
MEdge &e = es[i];
if (e.cap && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = i;
a[e.to] = min(a[u], e.cap);
if (!in[e.to]) {
q.push(e.to);
in[e.to] = true;
}
}
}
}
return d[t] != INFF;
}
void solve() {
while (spfa()) {
flow += a[t];
cost += a[t] * d[t];
int u = t;
while (u != s) {
es[p[u]].cap -= a[t];
es[p[u] ^ 1].cap += a[t];
u = es[p[u]].from;
}
}
}
};
int ma[105][105];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> ma[i][j];
}
}
int s = 0;
int tot = n * (n + 2) + 2;
int t = tot - 1;
MCMF mc = MCMF(tot, s, t);
for (int i = 1; i <= n; i++) {
mc.add_edge(s, n * n + i, 1, 0.0);
}
for (int i = 1; i <= n; i++) {
mc.add_edge(n * n + n + i, t, 1, 0.0);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
mc.add_edge(n * n + i, n * (j - 1) + i, 1, 0.0);
mc.add_edge(n * (j - 1) + i, n * n + n + j, 1, -log10(ma[j][i]));
}
}
mc.solve();
for (int i = n * n + 1; i <= n * n + n; i++) {
for (auto ii : mc.G[i]) {
MEdge e = mc.es[ii];
if (e.cap == 0) {
if (i == n * n + n)
cout << (e.to - 1) / n + 1;
else
cout << (e.to - 1) / n + 1 << " ";
}
}
}
}