[luoguP2045] 方格取数加强版(最小费用最大流)

传送门

水题

——代码

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #define N 51
  6 #define M 100001
  7 #define INF 1e9
  8 #define min(x, y) ((x) < (y) ? (x) : (y))
  9
 10 int n, k, s, t, cnt, tot, sum;
 11 int head[M], to[M], val[M], cost[M], next[M], dis[M], pre[M], a[N][N], b[N][N];
 12 bool vis[M];
 13
 14 inline int read()
 15 {
 16     int x = 0, f = 1;
 17     char ch = getchar();
 18     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
 19     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
 20     return x * f;
 21 }
 22
 23 inline void add2(int x, int y, int z, int c)
 24 {
 25     to[cnt] = y;
 26     val[cnt] = z;
 27     cost[cnt] = c;
 28     next[cnt] = head[x];
 29     head[x] = cnt++;
 30 }
 31
 32 inline void add(int x, int y, int z, int c)
 33 {
 34     add2(x, y, z, c);
 35     add2(y, x, 0, -c);
 36 }
 37
 38 inline bool spfa()
 39 {
 40     int i, u, v;
 41     std::queue <int> q;
 42     memset(vis, 0, sizeof(vis));
 43     memset(pre, -1, sizeof(pre));
 44     memset(dis, 127 / 3, sizeof(dis));
 45     q.push(s);
 46     dis[s] = 0;
 47     while(!q.empty())
 48     {
 49         u = q.front(), q.pop();
 50         vis[u] = 0;
 51         for(i = head[u]; i ^ -1; i = next[i])
 52         {
 53             v = to[i];
 54             if(val[i] && dis[v] > dis[u] + cost[i])
 55             {
 56                 dis[v] = dis[u] + cost[i];
 57                 pre[v] = i;
 58                 if(!vis[v])
 59                 {
 60                     q.push(v);
 61                     vis[v] = 1;
 62                 }
 63             }
 64         }
 65     }
 66     return pre[t] ^ -1;
 67 }
 68
 69 int main()
 70 {
 71     int i, j, x, d;
 72     n = read();
 73     k = read();
 74     s = 0, t = (n * n << 1) + 1;
 75     memset(head, -1, sizeof(head));
 76     for(i = 1; i <= n; i++)
 77         for(j = 1; j <= n; j++)
 78         {
 79             x = read(), b[i][j] = ++tot;
 80             add(b[i][j], b[i][j] + n * n, 1, -x);
 81             add(b[i][j], b[i][j] + n * n, INF, 0);
 82         }
 83     for(i = 1; i <= n; i++)
 84         for(j = 1; j <= n; j++)
 85         {
 86             if(i < n) add(b[i][j] + n * n, b[i + 1][j], INF, 0);
 87             if(j < n) add(b[i][j] + n * n, b[i][j + 1], INF, 0);
 88         }
 89     add(s, 1, k, 0);
 90     add(n * n << 1, t, k, 0);
 91     while(spfa())
 92     {
 93         d = INF;
 94         for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]]) d = min(d, val[i]);
 95         for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]])
 96         {
 97             val[i] -= d;
 98             val[i ^ 1] += d;
 99         }
100         sum += dis[t] * d;
101     }
102     printf("%d\n", -sum);
103     return 0;
104 }

时间: 2025-01-18 13:18:38

[luoguP2045] 方格取数加强版(最小费用最大流)的相关文章

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

网络流24题的坑还没填完就来搞其他题,你真的要TJ? 写这题给自己的费用流攒个模板. 题目大意:一个n*n的矩阵,每格有点权,从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大. 啊简单的费用流.每个点i拆成i和i',连一条容量为1的边价值为点权,再连一条容量inf的边价值为0来让这个点能被经过,然后S连(1,1)容量k价值0,i'和右.下的点连容量inf价值0的边,(n,n)'连T容

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 其实就是这几道题 在一个有m*n 个方格的棋盘中 每个方格中有一个正整数 现要从在方格中从左上角到右下角取数,只能向右或向下走 每走到一个格子就可以把这个位置上的数取走(下次经过就没有了) 1.让你走1次,求取出的数的总和最大是多少 2.让你走2次,求取出的数的总和最大是多少 3.让你走k次,求取出的数的总和最大是多少 对于第一问,十分显然. 设\(f[i][j]\)表示\(i\)行\(j\)列的最大价值,转移即可. 第二问,

HDU 3376 &amp;&amp; 2686 方格取数 最大和 费用流裸题

题意: 1.一个人从[1,1] ->[n,n] ->[1,1] 2.只能走最短路 3.走过的点不能再走 问最大和. 对每个点拆点限流为1即可满足3. 费用流流量为2满足1 最大费用流,先给图取负,结果再取负,满足2 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <set&

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

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

Luogu P2045 方格取数加强版 题解

闲扯 所以我还是不会做网络流啊... 打个模板多轻松啊,为什么还要建图呢,天空这么蓝,森林那么绿,这个世界多么美好啊! 建图的套路感觉好多啊..还是慢慢学吧.. Solution 题目分析/建图 因为限制了方向,同时还限制了每一个最多取一次,要求和最大,想到了什么?什么都没想到 最大费用最大流! 因为每个点只能选一次,所以我们考虑把这个点拆开,变成一个入点,一个出点,然后在入点和出点之间连上一条流量为 \(1\) ,费用为 \(val_i\) 的边.但是每一个的数取了后还是可以经过这个位置的,所

【Codevs1227】方格取数2(费用流)

题意:给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000) 现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0, 这样一共走K次,现在要求K次所达到的方格的数的和最大. n<=50,k<=10 思路:费用流 将每个点裂成一个出点和一个入点(i,j,1..2),这个思路与最大流类似 (i,j,1)->(i,j,2) 连两条边: 容量为1,费用为a[i,j] 容量为K,费用为0 (i,j,2)->

poj 3422 洛谷P2045 K取方格数(方格取数加强版)

Description: 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大 Input: 第一行两个数n,k(1<=n<=50, 0<=k<=10) 接下来n行,每行n个数,分别表示矩阵的每个格子的数 Output: 一个数,为最大和 思路:仍旧是拆点 因为每个点都有一个限制K和一个价

P2045 方格取数加强版

题目描述 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大 输入输出格式 输入格式: 第一行两个数n,k(1<=n<=50, 0<=k<=10) 接下来n行,每行n个数,分别表示矩阵的每个格子的数 输出格式: 一个数,为最大和 输入输出样例 输入样例#1: 3 1 1 2 3 0 2

[Luogu2045] 方格取数加强版

题目描述 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大 输入输出格式 输入格式: 第一行两个数n,k(1<=n<=50, 0<=k<=10) 接下来n行,每行n个数,分别表示矩阵的每个格子的数 输出格式: 一个数,为最大和 输入输出样例 输入样例#1: 复制 3 1 1 2 3 0