[Luogu2045] 方格取数加强版
题目描述
给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大
输入输出格式
输入格式:第一行两个数n,k(1<=n<=50, 0<=k<=10)
接下来n行,每行n个数,分别表示矩阵的每个格子的数
输出格式:一个数,为最大和
输入输出样例
说明
每个格子中的数不超过1000
拆点, 费用流。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; #define reg register inline char gc() { static const int BS = 1 << 22; static unsigned char buf[BS], *st, *ed; if (st == ed) ed = buf + fread(st = buf, 1, BS, stdin); return st == ed ? EOF : *st++; } #define gc getchar inline int read() { int res=0;char ch=gc();bool fu=0; while(!isdigit(ch)){if(ch=='-')fu=1;ch=gc();} while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=gc(); return fu?-res:res; } #define N 5010 #define M 200010 int n, k; int a[55][55]; int S, T; int ans; struct edge { int nxt, to, flow, val; }ed[M]; int head[N], cnt = 1; inline void add(int x, int y, int z, int c) { ed[++cnt] = (edge){head[x], y, z, c}; head[x] = cnt; ed[++cnt] = (edge){head[y], x, 0, -c}; head[y] = cnt; } inline int id(int i, int j, int k) { return (i - 1) * n + j + k * n * n; } int incf[N], dis[N], pre[N]; bool ex[N]; inline bool spfa() { memset(dis, 0xcf, sizeof dis); memset(ex, 0, sizeof ex); queue <int> q; q.push(S); dis[S] = 0; incf[S] = 1 << 25; while(!q.empty()) { int x = q.front();q.pop(); ex[x] = 0; for (reg int i = head[x] ; i ; i = ed[i].nxt) { if (ed[i].flow) { int to = ed[i].to; if (dis[to] < dis[x] + ed[i].val) { dis[to] = dis[x] + ed[i].val; pre[to] = i; incf[to] = min(incf[x], ed[i].flow); if (!ex[to]) ex[to] = 1, q.push(to); } } } } return dis[T] != 0xcfcfcfcf; } inline void update() { int x = T; while(x != S) { int i = pre[x]; ed[i].flow -= incf[T]; ed[i^1].flow += incf[T]; x = ed[i^1].to; } ans += dis[T] * incf[T]; } int main() { n = read(), k = read(); for (reg int i = 1 ; i <= n ; i ++) for (reg int j = 1 ; j <= n ; j ++) a[i][j] = read(); S = 1, T = 2 * n * n; for (reg int i = 1 ; i <= n ; i ++) for (reg int j = 1 ; j <= n ; j ++) { add(id(i, j, 0), id(i, j, 1), 1, a[i][j]); add(id(i, j, 0), id(i, j, 1), k - 1, 0); if (j + 1 <= n) add(id(i, j, 1), id(i, j + 1, 0), k, 0); if (i + 1 <= n) add(id(i, j, 1), id(i + 1, j, 0), k, 0); } while(spfa()) update(); printf("%d\n", ans); return 0; }