洛谷-2045 方格取数加强版

题目描述
给出一个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

解释:这里我们用最大费用流解决这个问题,对每个格子我们拆成两个点,出点和入点(in+j和in+j+nn),出点和入点直接有两条边,一条是容量为1价格为负的格子的值,另一条为容量无限价格为0,再连好格子之间的相互连接,最后跑0到2n*n-1的最大费用模版就好了。

#include<iostream>
#include<vector>
#define N 6666
#define INF 100000009
using namespace std;
struct edge{
    int to,cap,cost,rev;
};
int V;
vector<edge> G[N];
int dist[N]={0};
int prevv[N],preve[N];
void add_edge(int from,int to,int cap,int cost){
    G[from].push_back(edge{to,cap,cost,G[to].size()});
    G[to].push_back(edge{from,0,-cost,G[from].size()-1});
}
int min_cost_flow(int s,int t,int f){
    int res=0;
    while(f){
        fill(dist,dist+V,INF);
        dist[s]=0;
        bool update=true;
        while(update){
            update=false;
            for(int v=0;v<V;v++){
                if(dist[v]==INF) continue;
                for(int i=0;i<G[v].size();i++){
                    edge &e=G[v][i];
                    if(e.cap>0&&dist[e.to]>dist[v]+e.cost){
                        dist[e.to]=dist[v]+e.cost;
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        update=true;
                    }
                }
            }
        }
        if(dist[t]==INF){
            return -1;
        }
        int d=f;
        for(int v=t;v!=s;v=prevv[v]){
            d=min(d,G[prevv[v]][preve[v]].cap);
        }
        f-=d;
        res+=d*dist[t];
        for(int v=t;v!=s;v=prevv[v]){
            edge &e=G[prevv[v]][preve[v]];
            e.cap-=d;
            G[v][e.rev].cap+=d;
        }
    }
    return res;
}
int n=0,m=0;
int a;
bool ok(int x,int y){
    if(x<n&&x>=0&&y<n&&y>=0) return 1;
    return 0;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>a;
            add_edge(i*n+j,i*n+j+n*n,1,-a);
            add_edge(i*n+j,i*n+j+n*n,INF,0);
            if(ok(i-1,j)) add_edge((i-1)*n+j+n*n,i*n+j,INF,0);
            if(ok(i,j-1)) add_edge(i*n+j-1+n*n,i*n+j,INF,0);
        }
    }
    V=2*n*n;
    cout<<-min_cost_flow(0,2*n*n-1,m)<<endl;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值