$ \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. Win7 IE11 F2无法切换版本

    Win7 IE11 F2无法切换版本 http://www.microsoft.com/zh-cn/download/confirmation.aspx?id=45154 选择操作系统对应的版本 ht ...

  2. error: undefined reference to 'av_register_all()'

    cygwin下ndk编译工程中使用ffmpeg时出现的错误:“error: undefined reference to 'av_register_all()'” 使用ffmpeg的源文件是  *.c ...

  3. 【知识碎片】JavaScript篇

     40.选择器组合 逗号是多选择器空格 是子子孙孙尖括号 只找儿子 39.失去焦点事件blur $("input").blur(function(){ $("input& ...

  4. Python代码的编译

    Python代码的编译 Python代码在解释执行之前,是会被编译成.pyc或者.pyo文件的,它们是中间字节码表示的文件,之后Python虚拟机才会去解释执行它们. 1.pyc文件 ======== ...

  5. 用rand5()生成rand(n)

    问题:有函数rand5(),它能够等概率生成[0,5)之间的整数.由rand5()构造rand(n)使其能够等概率生成[0,n)之间的整数. 思路1:有rand5()先生成等概率生成0和1的rand0 ...

  6. 【CF#338D】GCD Table

    [题目描述] 有一张N,M<=10^12的表格,i行j列的元素是gcd(i,j) 读入一个长度不超过10^4,元素不超过10^12的序列a[1..k],问是否在某一行中出现过 [题解] 要保证g ...

  7. angular.js简单入门。

    小弟刚接触angular js  就写了一个简单的入门.后续慢慢补... 首先看 html 页面. <html> <meta charset="UTF-8"> ...

  8. js 线程和进程的关系

    进程(process)和线程(thread)是操作系统的基本概念 1.计算机的核心是CPU,它承担了所有的计算任务 2.单个CPU一次只能运行一个任务 3.进程它代表CPU所能处理的单个任务.任一时刻 ...

  9. 14-stringstream

    C++中stringstream的使用方法和样例 原创 2016年11月06日 15:46:49 标签: string / C++ 7427 之前在leetcode中进行string和int的转化时使 ...

  10. win32多线程(三) 死锁

    任何时候当一段代码需要两个(或更多)资源时,都有潜在性的死锁. void SwapLists(List *list1, List *list2) { List *tmp_list; EnterCrit ...