codevs 1227 方格取数 2 【网络流+费用流基础】

来源:互联网 发布:9分钟进5球 知乎 编辑:程序博客网 时间:2024/05/22 17:20

codevs 1227 方格取数 2 【网络流+费用流基础】


1227 方格取数 2

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
题目描述 Description

给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大

输入描述 Input Description

第一行两个数n,k(1<=n<=50, 0<=k<=10)

接下来n行,每行n个数,分别表示矩阵的每个格子的数

输出描述 Output Description

一个数,为最大和

样例输入 Sample Input

3 1

1 2 3

0 2 1

1 4 2

样例输出 Sample Output

11



csdn 插入代码的时候 有问题 唉  大家将就将就  或者把代码复制到到编译器中查看

题解

把点  一分为二  因为一个数只能取一次 所以流量为1 费用为权值

然后每个点 添加一条边到它的左边和下边 流量为k 费用为0

源点S 添加K条边到点1

点n*n和n*n*2添加k条边到T


#include <stdio.h>
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
class E{
 public:
  int to,next,c,w;
};
E e[40005];
int next[5005],pree[5005],dis[5005],pre[5005],vis[5005];
int n,k,ans,cnt=1,s=0,t=5002;
void add(int from,int to,int c,int w){
 e[++cnt].to=to;e[cnt].next=next[from];e[cnt].c=c;e[cnt].w=w;next[from]=cnt;
 e[++cnt].to=from;e[cnt].next=next[to];e[cnt].c=0;e[cnt].w=-w;next[to]=cnt;
}
int spfa(){
 memset(dis,127,sizeof(dis));
 memset(vis,0,sizeof(vis));
 dis[s]=0;
 vis[s]=1;
 queue<int> q;
 q.push(s);
 while(q.size()){
  int u=q.front();q.pop();vis[u]=0;
  for(int i=next[u];i;i=e[i].next){
   int v=e[i].to;
   if(e[i].c && dis[u]+e[i].w<dis[v]){
    dis[v]=dis[u]+e[i].w;
    pre[v]=u;pree[v]=i;
    if(!vis[v]){
     q.push(v);
     vis[v]=1;
    }
   }
  }
 }
 if(dis[t]<(1<<28)) return 1;
 return 0;
}
void mcf(){
 for(int i=pree[t],u=pre[t];i;i=pree[u],u=pre[u]){
  ans+=e[i].w;
  e[i].c--;
  e[i^1].c++;
 }
}
int main(){
 cin>>n>>k;
 int w;
 for(int i=1;i<=n;i++){
  for(int j=1;j<=n;j++){
   cin>>w;
   int a=(i-1)*n+j,b=(i-1)*n+j+1,c=i*n+j,d=(i-1)*n+j+n*n;
   add(a,d,1,-w);
   if(j<n) add(a,b,k,0),add(d,b,1,0);
   if(i<n) add(a,c,k,0),add(d,c,1,0);
  }
 }
 add(s,1,k,0);
 add(n*n,t,k,0);
 add(n*n*2,t,k,0);
 while(spfa()) mcf();
 cout<<-ans;
    return 0;




0 0