$ \color{#0066ff}{ 题目描述 }$

给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大

\(\color{#0066ff}{输入格式}\)

第一行两个数n,k(1<=n<=50, 0<=k<=10)

接下来n行,每行n个数,分别表示矩阵的每个格子的数

\(\color{#0066ff}{输出格式}\)

一个数,为最大和

\(\color{#0066ff}{输入样例}\)

3 1
1 2 3
0 2 1
1 4 2

\(\color{#0066ff}{输出样例}\)

11

\(\color{#0066ff}{数据范围与提示}\)

每个格子中的数不超过1000

\(\color{#0066ff}{题解}\)

拆点,矩阵每个元素拆成入点和出点

入点向出点连容量为1, 权值为点权的边,代表只能选一次

入点再向出点连容量为inf,权值为0的边,代表之后也能走这个格子,但是无法获得权值

最大费用最大流即可(这里用了ZKWqwq)

#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int inf = 0x7fffffff;
const int maxn = 1e5 + 10;
struct node {
int to, can, dis;
node *nxt, *rev;
node(int to = 0, int can = 0, int dis = 0, node *nxt = NULL): to(to), can(can), dis(dis), nxt(nxt) {
rev = NULL;
}
};
node *head[maxn];
bool vis[maxn];
int dis[maxn], mp[100][100];
int n, k, s, t;
void add(int from, int to, int can, int dis) {
head[from] = new node(to, can, dis, head[from]);
}
void link(int from, int to, int can, int dis) {
add(from, to, can, dis);
add(to, from, 0, -dis);
head[from]->rev = head[to];
head[to]->rev = head[from];
}
bool spfa() {
for(int i = s; i <= t; i++) vis[i] = false, dis[i] = -inf;
std::deque<int> q;
q.push_back(t);
dis[t] = 0;
while(!q.empty()) {
int tp = q.front(); q.pop_front();
vis[tp] = false;
for(node *i = head[tp]; i; i = i->nxt) {
if(dis[i->to] < dis[tp] - i->dis && i->rev->can) {
dis[i->to] = dis[tp] - i->dis;
if(!vis[i->to]) {
if(!q.empty() && dis[i->to] > dis[q.front()]) q.push_front(i->to);
else q.push_back(i->to);
vis[i->to] = true;
}
}
}
}
return dis[s] != -inf;
}
int dfs(int x, int change) {
if(x == t || !change) return change;
int flow = 0, ls;
vis[x] = true;
for(node *i = head[x]; i; i = i->nxt) {
if(!vis[i->to] && dis[i->to] == dis[x] - i->dis && (ls = dfs(i->to, std::min(change, i->can)))) {
flow += ls;
change -= ls;
i->can -= ls;
i->rev->can += ls;
if(!change) break;
}
}
return flow;
}
int zkw() {
int cost = 0;
while(spfa()) {
vis[t] = true;
while(vis[t]) {
for(int i = s; i <= t; i++) vis[i] = false;
cost += dis[s] * dfs(s, inf);
}
}
return cost;
} int id(int x, int y) { return (x - 1) * n + y; } int main() {
n = in(), k = in();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
mp[i][j] = in();
s = 0, t = 2 * n * n + 1;
link(s, id(1, 1), k, 0);
link(id(n, n) + n * n, t, k, 0);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) {
if(i + 1 <= n) link(n * n + id(i, j), id(i + 1, j), inf, 0);
if(j + 1 <= n) link(n * n + id(i, j), id(i, j + 1), inf, 0);
link(id(i, j), n * n + id(i, j), 1, mp[i][j]);
link(id(i, j), n * n + id(i, j), inf, 0);
}
printf("%d", zkw());
return 0;
}

P2045 方格取数加强版 最大费用最大流的更多相关文章

  1. 洛谷 P2045 方格取数加强版【费用流】

        题目链接:https://www.luogu.org/problemnew/show/P2045 题目描述 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现 ...

  2. P2045 方格取数加强版

    P2045 方格取数加强版 题目描述 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格 ...

  3. bzoj P2045 方格取数加强版【最大费用最大流】

    今天脑子不太清醒,把数据范围看小了一直TTTTLE-- 最大费用最大流,每个格子拆成两个(x,y),(x,y)',(x,y)向(x,y)'连一条费用a[x][y]流量1的边表示选的一次,再连一条费用0 ...

  4. 洛谷P2045 方格取数加强版(费用流)

    题意 题目链接 Sol 这题能想到费用流就不难做了 从S向(1, 1)连费用为0,流量为K的边 从(n, n)向T连费用为0,流量为K的边 对于每个点我们可以拆点限流,同时为了保证每个点只被经过一次, ...

  5. 【Luogu】P2045方格取数加强版(最小费用最大流)

    题目链接 通过这题我学会了引诱算法的行为,就是你通过适当的状态设计,引诱算法按照你想要它做的去行动,进而达到解题的目的. 最小费用最大流,首先将点拆点,入点和出点连一条费用=-权值,容量=1的边,再连 ...

  6. [洛谷P2045]方格取数加强版

    题目大意:有一个n*n的矩阵,每个格子有一个非负整数,规定一个人从(1,1)开始,只能往右或下走,走到(n,n)为止,并把沿途的数取走,取走后数变为0.这个人共取n次,求取得的数的最大总和. 解题思路 ...

  7. [CodeVs1227]方格取数2(最大费用最大流)

    网络流24题的坑还没填完,真的要TJ? 题目大意:一个n*n的矩阵,每格有点权,从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走 ...

  8. 洛谷 - P2045 - 方格取数加强版 - 费用流

    原来这种题的解法是费用流. 从一个方格的左上走到右下,最多走k次,每个数最多拿走一次. 每次走动的流量设为1,起始点拆点成限制流量k. 每个点拆成两条路,一条路限制流量1,费用为价值相反数.另一条路无 ...

  9. 洛谷P2045 方格取数加强版 最小费用流

    Code: #include<cstdio> #include<cstring> #include<algorithm> #include<queue> ...

随机推荐

  1. 【技术调研】最强Node-RED初探总结

    在某个项目中需要调研下node-red的功能,我大概花了三天时间研究了相关的官方文档,写了几个Demo总结了下node-red相关的功能.如需转载,请注明出处 https://www.cnblogs. ...

  2. 每天一个Linux命令 - 【find】

    命令:find 用途:查找文件并执行指令的操作 [语法]:find [路径] [选项] [参数] [功能介绍]:find命令在指定的目录下查找文件.find命令还能够对查找到的文件执行的指定的操作,通 ...

  3. ansible基本使用

    ansible介绍 基础概念 ansible是个配置管理工具,可以批量处理一些任务.ansible只需要依赖ssh即可使用,而不需要在受管主机上安装客户端工具. ansible具有幂等性,即以结果为导 ...

  4. Python基础—流程控制

    一.Python流程控制 计算机程序在解决某个具体问题时,包括三种情形,即顺序执行所有的语句.选择执行部分的语句和循环执行部分语句,这正好对应着程序设计中的三种程序执行结构流程:顺序结构.选择结构和循 ...

  5. android 4.0.4系统下实现apk的静默安装和启动

    转 android 4.0.4系统下实现apk的静默安装和启动 分类: Android 2013-02-14 14:13 1762人阅读 评论(10) 收藏 举报 最近在android 4.0.4系统 ...

  6. Unity抗锯齿的设置

    [Unity抗锯齿的设置] "Edit"->"Project Settings"->"Quality",可以质量设置Inspec ...

  7. CrackMe的简单破解

    [CrackMe的简单破解] 对于以下这样的输入账号和密码的窗口,我们可以猜测该程序使用最简单的机制实现,即用strmp来比较用户输入的密码和原始密码匹配.所以为了破解该程序,可以通过bp strmp ...

  8. Codeforces 919F——A Game With Numbers

    转自大佬博客:https://www.cnblogs.com/NaVi-Awson/p/8405966.html; 题意 两个人 Van♂ 游戏,每人手上各有 8'>88 张牌,牌上数字均为 [ ...

  9. PHP格式化(文件)存储数据大小(SIZE)显示

    有时候我们需要在网页上显示某个文件的大小,或者是其它数据的大小数字. 这个数字往往从跨度很大,如果以B为单位的话可能是个位,如果1G则长达1073741824的数字,这个时候我们就需要根据大小来格式化 ...

  10. 跨平台的图形软件Dia

    一款非常不错的软件Dia,软件很小,免费.好用.跨平台(linux.windows.mac).可导出多种格式图片,除了流程图.UML建模图,还可以绘制其他很多图. ubuntu下可以直接通过命令行su ...