-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMaxCutInference.cpp
159 lines (137 loc) · 3.52 KB
/
MaxCutInference.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Special-purpose {0,1} combinatorial optimization solver for
// problems of the following by a reduction to graph cuts:
//
// minimize sum_i psi_i(x[i])
// x[1]...x[n] in {0,1} + sum_{i < j} phi_{ij}(x[i], x[j])
//
// where
// psi_i : {0, 1} --> R
// phi_{ij} : {0, 1} x {0, 1} --> R
//
// such that
// phi_{ij}(0,0) + phi_{ij}(1,1) <= phi_{ij}(0,1) + phi_{ij}(1,0) (*)
//
// This can also be used to solve maximization problems where the
// direction of the inequality in (*) is reversed.
//
// INPUT: phi -- a matrix such that phi[i][j][u][v] = phi_{ij}(u, v)
// psi -- a matrix such that psi[i][u] = psi_i(u)
// x -- a vector where the optimal solution will be stored
//
// OUTPUT: value of the optimal solution
//
// To use this code, create a GraphCutInference object, and call the
// DoInference() method. To perform maximization instead of minimization,
// ensure that #define MAXIMIZATION is enabled.
#include <vector>
#include <iostream>
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<VVI> VVVI;
typedef vector<VVVI> VVVVI;
const int INF = 1000000000;
// comment out following line for minimization
#define MAXIMIZATION
struct GraphCutInference {
int N;
VVI cap, flow;
VI reached;
int Augment(int s, int t, int a) {
reached[s] = 1;
if (s == t) return a;
for (int k = 0; k < N; k++) {
if (reached[k]) continue;
if (int aa = min(a, cap[s][k] - flow[s][k])) {
if (int b = Augment(k, t, aa)) {
flow[s][k] += b;
flow[k][s] -= b;
return b;
}
}
}
return 0;
}
int GetMaxFlow(int s, int t) {
N = cap.size();
flow = VVI(N, VI(N));
reached = VI(N);
int totflow = 0;
while (int amt = Augment(s, t, INF)) {
totflow += amt;
fill(reached.begin(), reached.end(), 0);
}
return totflow;
}
int DoInference(const VVVVI &phi, const VVI &psi, VI &x) {
int M = phi.size();
cap = VVI(M+2, VI(M+2));
VI b(M);
int c = 0;
for (int i = 0; i < M; i++) {
b[i] += psi[i][1] - psi[i][0];
c += psi[i][0];
for (int j = 0; j < i; j++)
b[i] += phi[i][j][1][1] - phi[i][j][0][1];
for (int j = i+1; j < M; j++) {
cap[i][j] = phi[i][j][0][1] + phi[i][j][1][0] - phi[i][j][0][0] - phi[i][j][1][1];
b[i] += phi[i][j][1][0] - phi[i][j][0][0];
c += phi[i][j][0][0];
}
}
#ifdef MAXIMIZATION
for (int i = 0; i < M; i++) {
for (int j = i+1; j < M; j++)
cap[i][j] *= -1;
b[i] *= -1;
}
c *= -1;
#endif
for (int i = 0; i < M; i++) {
if (b[i] >= 0) {
cap[M][i] = b[i];
} else {
cap[i][M+1] = -b[i];
c += b[i];
}
}
int score = GetMaxFlow(M, M+1);
fill(reached.begin(), reached.end(), 0);
Augment(M, M+1, INF);
x = VI(M);
for (int i = 0; i < M; i++) x[i] = reached[i] ? 0 : 1;
score += c;
#ifdef MAXIMIZATION
score *= -1;
#endif
return score;
}
};
int main() {
// solver for "Cat vs. Dog" from NWERC 2008
int numcases;
cin >> numcases;
for (int caseno = 0; caseno < numcases; caseno++) {
int c, d, v;
cin >> c >> d >> v;
VVVVI phi(c+d, VVVI(c+d, VVI(2, VI(2))));
VVI psi(c+d, VI(2));
for (int i = 0; i < v; i++) {
char p, q;
int u, v;
cin >> p >> u >> q >> v;
u--; v--;
if (p == 'C') {
phi[u][c+v][0][0]++;
phi[c+v][u][0][0]++;
} else {
phi[v][c+u][1][1]++;
phi[c+u][v][1][1]++;
}
}
GraphCutInference graph;
VI x;
cout << graph.DoInference(phi, psi, x) << endl;
}
return 0;
}