1. 程式人生 > >[Luogu2045] 方格取數加強版

[Luogu2045] 方格取數加強版

bsp namespace != 說明 oid include code radi 現在

題目描述

給出一個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 1
1 4 2
輸出樣例#1: 復制
11

說明

每個格子中的數不超過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; }

[Luogu2045] 方格取數加強版