网络流大法吼

不想用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

洛谷P1004 方格取数的更多相关文章

  1. 棋盘DP三连——洛谷 P1004 方格取数 &&洛谷 P1006 传纸条 &&Codevs 2853 方格游戏

    P1004 方格取数 题目描述 设有N $\times N$N×N的方格图(N $\le 9$)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字00.如下图所示(见样例): A ...

  2. 洛谷 P1004 方格取数 题解

    P1004 方格取数 题目描述 设有 \(N \times N\) 的方格图 \((N \le 9)\),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字\(0\).如下图所示(见样例): ...

  3. 洛谷 P1004 方格取数 【多进程dp】

    题目链接:https://www.luogu.org/problemnew/show/P1004 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 ...

  4. 洛谷 P1004 方格取数

    题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 ...

  5. 【动态规划】洛谷P1004方格取数

    题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 ...

  6. 洛谷P1004 方格取数-四维DP

    题目描述 设有 N \times NN×N 的方格图 (N \le 9)(N≤9) ,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 00 .如下图所示(见样例): A 0 0 0 0 0 ...

  7. Codevs 1043 ==洛谷 P1004 方格取数

    题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 ...

  8. 洛谷 P1004 方格取数 【多线程DP/四维DP/】

    题目描述(https://www.luogu.org/problemnew/show/1004) 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0. ...

  9. 四维动规 洛谷P1004方格取数

    分析:这个题因为数据量非常小,可以直接用四维的DP数组 dp[i][j][k][l]表示第一个人走到位置(i,j),第二个人走到位置[k][l]时所取的数的最大和 状态转移方程可以轻松得出为:dp[i ...

随机推荐

  1. Problem 8

    Problem 8 # Problem_8.py """ The four adjacent digits in the 1000-digit number that h ...

  2. Emgu cv人脸检测识别

    Emgu cv人脸检测识别 1.开发平台:WIN10 X64    VS2012    Emgucv版本:3.1 2.先给大家分享一个官网给的示例源代码: https://ncu.dl.sourcef ...

  3. jQuery练习总结(二)

    --------------------------------------- <!DOCTYPE html> <!DOCTYPE HTML PUBLIC "-//W3C/ ...

  4. svn查看工程版本库的url地址

    打开cmd,cd到工程目录,使用svn的命令:svn info 完.

  5. html5 过程解决问题收集

    1.使用画布时报错误: Uncaught TypeError: Object [object Object] has no method 'getContext' . 解决方法: $(function ...

  6. CAD教程-AL对其命令

    AL可以实现不规则的对其功能 1.第一步按下AL,按下Enter 2.选择第一个源点 3.选择第一个目标点 4.选择第二个源点 5.选择第二个目标点 6.按下Enter,完成移位

  7. HDU 2815

    特判B不能大于等于C 高次同余方程 #include <iostream> #include <cstdio> #include <cstring> #includ ...

  8. Codeves 2800 送外卖 状态压缩DP+floyd

    送外卖     题目描述 Description 有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上.n个不同的客户分别在1~n个编号的城市中.送外卖的从0号城市出发,然后 ...

  9. 蓝桥杯--算法提高 排列数 (简单dfs)

    算法提高 排列数   时间限制:1.0s   内存限制:256.0MB      问题描述 0.1.2三个数字的全排列有六种,按照字母序排列如下: 012.021.102.120.201.210 输入 ...

  10. 内存问题检测神器:Valgrind

    Linux下内存问题检测神器:Valgrind 在写大型C/C++工程时难免会发生内存泄漏现象,系统编程中一个重要的方面就是有效地处理与内存相关的问题.你的工作越接近系统,你就需要面对越多的内存问题. ...