[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 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;
}

 

 

 

posted @ 2018-08-30 12:04  zZhBr  阅读(170)  评论(0编辑  收藏  举报