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 1
1 4 2

输出样例#1:

11

说明

每个格子中的数不超过1000

Solution:

  本题费用流套路题(道道网络流题都是满满的套路啊!)。

  分析怎么想到费用流:

    首先$k=1$就是sb动规,而当$k>1$就要限制每个点只能选$1$次,这样限制了上下界且带权的最优性问题,直接考虑费用流模型。

  怎么建模:

    1、拆点肯定是要的,因为有选择次数限制,那么点$i$向$i‘$连容量$1$费用为点权的边,又因还能选k-1次,所以再从$i$向$i‘$连容量$k-1$费用$0$的边。

    2、对于能转移的一对点$i\rightarrow j$,从$i‘$向$j$连容量$k$费用$0$的边。

  以$(1,1)$的入点为原点,$(n,n)$的出点为汇点,因为既保证了一个点权值只会贡献一次,也保证了选了k条路线(最大流一定为k),所以满足正确性,直接跑最大费用最大流就好了。

代码:

/*Code by 520 -- 8.25*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
using namespace std;
const int N=50005,inf=-2139062144;
int n,k,s,t,maxn[N],pre[N],dis[N],tot;
int cnt=1,h[N],to[N],net[N],w[N],c[N];
int maxc,maxf,mp[55][55],id[55][55];
bool vis[N];

il void add(int u,int v,int fl,int co){
    to[++cnt]=v,net[cnt]=h[u],w[cnt]=fl,c[cnt]=co,h[u]=cnt;
    to[++cnt]=u,net[cnt]=h[v],w[cnt]=0,c[cnt]=-co,h[v]=cnt;
}

il bool spfa(){
    queue<int>q;
    memset(dis,128,sizeof(dis));
    dis[s]=0,maxn[s]=1<<30,q.push(s);
    while(!q.empty()){
        RE int u=q.front();q.pop();vis[u]=0;
        for(RE int i=h[u];i;i=net[i])
            if(w[i]&&dis[to[i]]<dis[u]+c[i]){
                dis[to[i]]=dis[u]+c[i],pre[to[i]]=i,
                maxn[to[i]]=min(maxn[u],w[i]);
                if(!vis[to[i]]) vis[to[i]]=1,q.push(to[i]);
            }
    }
    return dis[t]!=inf;
}

il void update(){
    int x=t;
    while(x!=s){
        RE int i=pre[x];
        w[i]-=maxn[t],w[i^1]+=maxn[t];
        x=to[i^1];
    }
    maxf+=maxn[t],maxc+=maxn[t]*dis[t];
}

il void init(){
    scanf("%d%d",&n,&k),s=1,t=2*n*n;
    For(i,1,n) For(j,1,n) {
        id[i][j]=++tot,scanf("%d",&mp[i][j]);
        add(id[i][j],id[i][j]+n*n,1,mp[i][j]),
        add(id[i][j],id[i][j]+n*n,k-1,0);
    }
    For(i,1,n) For(j,1,n){
        if(i+1<=n) add(id[i][j]+n*n,id[i+1][j],k,0);
        if(j+1<=n) add(id[i][j]+n*n,id[i][j+1],k,0);
    }
    while(spfa()) update();
    cout<<maxc;
}

int main(){
    init();
    return 0;
}

原文地址:https://www.cnblogs.com/five20/p/9537618.html

时间: 2024-10-08 06:21:42

P2045 方格取数加强版的相关文章

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

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

[洛谷P2045]方格取数加强版

题目大意:有一个n*n的矩阵,每个格子有一个非负整数,规定一个人从(1,1)开始,只能往右或下走,走到(n,n)为止,并把沿途的数取走,取走后数变为0.这个人共取n次,求取得的数的最大总和. 解题思路:由于取多少次不确定,所以不能用dp. 我们发现,一个格子只能从左边或上面走来,且数只能取到一次,那么我们可以把此题转化为最大费用最大流问题.首先拆点,将一个点拆成x和y,然后从x到y连一条容量为1,流量为x(x为这格的数)的边,然后再连一条容量为inf,费用为0的边,这样即可保证一个点可以走多次,

Luogu P2045 方格取数加强版 题解

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

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

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

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和一个价

[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

[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

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

P1004 方格取数

P1004 方格取数 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 0 0 0 0 0 7 0 0 0 0 0 0 14 0 0 0 0 0 21 0 0 0 4 0 0 0 0 15 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . B 某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角