网络流大法吼
不想用DP的我选择了用网络流……
建模方法:
从源点向(1,1)连一条容量为2(走两次),费用为0的边
从(n,n)向汇点连一条容量为2,费用为0的边
每个方格向右边和下边的方格连一条容量为inf,费用为0的边
走到每个方格,会取出方格上的数。每个方格的数只会被取走一次。
于是我们考虑拆点
每个方格向拆出的点连一条容量为1(只能被取走一次),费用为方格上的数的边
由于每个方格不一定只走一次,所以再连一条容量为inf,费用为0的边
然后跑最大费用最大流就行了~
我的代码中把边上的费用取相反数,跑最小费用最大流,最后得出的最小费用取负就是答案啦~!
下面是代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 210;
struct edge {
int flow, cap, cost, t, next;
}e[maxn * 50];
int n, m, s, t, p = -1, head[maxn], maxflow, mincost = 0, pre[maxn], dis[maxn], a[maxn][maxn];
bool vis[maxn];
void add_edge(int s, int t, int cap, int cost) {
p++;
e[p].t = t;
e[p].cap = cap;
e[p].cost = cost;
e[p].next = head[s];
head[s] = p;
}
bool spfa() {
queue < int > q;
while(!q.empty())q.pop();
memset(vis, 0, sizeof(vis));
vis[s] = 1;
q.push(s);
memset(dis, 0x7f, sizeof(dis));
memset(pre, -1, sizeof(pre));
dis[s] = 0;
while(!q.empty()) {
int k = q.front();
q.pop();
vis[k] = false;
for(int i = head[k]; i != -1; i = e[i].next) {
if(e[i].cap && dis[e[i].t] > dis[k] + e[i].cost) {
dis[e[i].t] = dis[k] + e[i].cost;
pre[e[i].t] = i;
if(!vis[e[i].t]) {
vis[e[i].t] = true;
q.push(e[i].t);
}
}
}
}
// for(int i = 0; i <= n * n; i++) cout << dis[i] << " ";
// cout << dis[t] << endl;
if(dis[t] == 0x7f7f7f7f) return false;
else return true;
}
void MCMF() {
while(spfa()) {
int mf = 0x7fffffff;
for(int i = pre[t]; i != -1; i = pre[e[i ^ 1].t]) {
mf = min(mf, e[i].cap);
// cout << i << " " << pre[e[i ^ 1].t] << endl;
// cout << e[2].cap << endl;
}
maxflow += mf;
for(int i = pre[t]; i != -1; i = pre[e[i ^ 1].t]) {
e[i].cap -= mf;
e[i ^ 1].cap += mf;
}
mincost += mf * dis[t];
}
}
int pos(int x, int y) {
return (x - 1) * n + y;
}
int main() {
memset(head, -1, sizeof(head));
cin >> n;
s = 0, t = maxn - 3;
int x, y, z;
while(1) {
cin >> x >> y >> z;
if(!(x || y || z)) break;
a[x][y] = z;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
add_edge(pos(i, j), pos(i, j) + n * n, 1, -a[i][j]);
add_edge(pos(i, j) + n * n, pos(i, j), 0, a[i][j]);
add_edge(pos(i, j), pos(i, j) + n * n, 0x7fffffff, 0);
add_edge(pos(i, j) + n * n, pos(i, j), 0, 0);
if(i < n) {
add_edge(pos(i, j) + n * n, pos(i + 1, j), 0x7fffffff, 0);
add_edge(pos(i + 1, j), pos(i, j) + n * n, 0, 0);
}
if(j < n) {
add_edge(pos(i, j) + n * n, pos(i, j + 1), 0x7fffffff, 0);
add_edge(pos(i, j + 1), pos(i, j) + n * n, 0, 0);
}
}
}
add_edge(s, pos(1, 1), 2, 0);
add_edge(pos(1, 1), s, 0, 0);
add_edge(pos(n, n) + n * n, t, 2, 0);
add_edge(t, pos(n, n) + n * n, 0, 0);
MCMF();
cout << -mincost << endl;
return 0;
}
qwq