行列染色,然后每个黑格子向白格子连边,然后二分图最大带权独立集。
别**把反向边流量给写成加了!
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
using int_t = long long int;
using std::cin;
using std::cout;
using std::endl;
const int_t LARGE = 11000;
const int_t SOURCE = LARGE - 1;
const int_t SINK = LARGE;
const int_t INF = 0x7fffffff;
struct Edge {
int_t to, capacity;
int_t flow = 0;
Edge* rev;
};
std::vector<Edge*> graph[LARGE + 1];
void pushEdge(int_t from, int_t to, int_t cap) {
Edge* e0 = new Edge{to, cap};
Edge* e1 = new Edge{from, 0};
e1->rev = e0;
e0->rev = e1;
graph[from].push_back(e0);
graph[to].push_back(e1);
#ifdef DEBUG
cout << "edge " << from << " " << to << " " << cap << endl;
#endif
}
int_t dis[LARGE + 1], visited[LARGE + 1], curr[LARGE + 1];
bool BFS() {
memset(curr, 0, sizeof(curr));
memset(visited, 0, sizeof(visited));
memset(dis, 0x3f, sizeof(dis));
dis[SOURCE] = 0;
std::queue<int_t> queue;
queue.push(SOURCE);
visited[SOURCE] = true;
while (queue.empty() == false) {
auto front = queue.front();
queue.pop();
// visited[front]=true;
for (auto edge : graph[front]) {
if (edge->capacity > edge->flow && visited[edge->to] == false) {
visited[edge->to] = true;
queue.push(edge->to);
dis[edge->to] = dis[front] + 1;
}
}
}
return visited[SINK];
}
int_t DFS(int_t vtx, int_t minf = INF) {
if (minf == 0 || vtx == SINK) return minf;
int_t result = 0;
for (int_t& i = curr[vtx]; i < graph[vtx].size(); i++) {
Edge* edge = graph[vtx][i];
if (dis[edge->to] != dis[vtx] + 1) continue;
int_t val = DFS(edge->to, std::min(minf, edge->capacity - edge->flow));
if (val > 0) {
minf -= val;
result += val;
edge->flow += val;
edge->rev->flow -= val;
if (minf == 0) break;
}
}
return result;
}
int_t execute() {
int_t result = 0;
while (BFS()) result += DFS(SOURCE);
return result;
}
int_t n, m;
int_t encode(int_t r, int_t c) { return (r - 1) * m + c; }
int main() {
// {
// cin >> n >> m >> SOURCE >> SINK;
// for (int_t i = 1; i <= m; i++) {
// int_t from, to, cap;
// cin >> from >> to >> cap;
// pushEdge(from, to, cap);
// }
// cout << execute() << endl;
// return 0;
// }
cin >> n >> m;
static int_t mat[LARGE + 1][LARGE + 1];
for (int_t i = 1; i <= n; i++)
for (int_t j = 1; j <= m; j++) cin >> mat[i][j];
int_t result = 0;
for (int_t i = 1; i <= n; i++) {
for (int_t j = 1; j <= m; j++) {
if ((i + j) % 2) {
const auto connect = [&](int_t r, int_t c) {
if (r >= 1 && r <= n && c >= 1 && c <= m) {
#ifdef DEBUG
cout << i << "," << j << "->" << r << "," << c << endl;
#endif
pushEdge(encode(i, j), encode(r, c), INF);
// #ifdef DEBUG
// cout<<"edge "
// #endif
}
};
connect(i + 1, j);
connect(i - 1, j);
connect(i, j + 1);
connect(i, j - 1);
pushEdge(SOURCE, encode(i, j), mat[i][j]);
} else {
pushEdge(encode(i, j), SINK, mat[i][j]);
}
result += mat[i][j];
}
}
cout << result - execute() << endl;
return 0;
}