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