P2045 方格取数加强版 最大费用最大流

$ \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;
}
posted @ 2019-03-05 19:15  olinr  阅读(160)  评论(0编辑  收藏  举报