codevs1227:方格取数2

题目描述 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

数据范围及提示 Data Size & Hint
1<=n<=50, 0<=k<=10
题目

芒果君:刚学的拆点,为数不多的自己写出来的网络流……理解题意后我们发现有以下几个要点:进行K次增广路;只能向右向下走;经过格点但可以不取数。那我们可以把每个格点拆成无权和有权的两个点。从其他点(同一位置有两个)走到该点,就走到无权点,流量视为inf,费用为0;当然也可以从同一点的无权走向有权,就是取出该数,只能取一次,流量是1,费用为负点权。左上连源点,右下连汇点。套KM的板子,最后的费用取相反数就是最大价值。注意建反边的费用是正边的相反数!

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<vector>
  7 #include<map>
  8 #include<set>
  9 #include<queue>
 10 #include<stack>
 11 #include<bitset>
 12 #include<string>
 13 #define maxn 20010
 14 using namespace std;
 15 typedef long long ll;
 16 const int inf=1<<29;
 17 queue<int>Q;
 18 int n,cnt,hl[maxn],s,t,k,vis[maxn],dis[maxn],pre[maxn],flow[maxn],id[maxn],tot;
 19 inline int cal(int x,int y){return (x-1)*n+y;}
 20 struct Edge{
 21     int u,v,c,f,ne,ctr;
 22 }e[200010];
 23 void add(int u,int v,int c,int f,int ctr)
 24 {
 25     e[++cnt].u=u;
 26     e[cnt].v=v;
 27     e[cnt].c=c;
 28     e[cnt].f=f;
 29     e[cnt].ctr=cnt+ctr;
 30     e[cnt].ne=hl[u];
 31     hl[u]=cnt;
 32 }
 33 bool bfs()
 34 {
 35     for(int i=0;i<=n*n*2+1;++i) dis[i]=inf,pre[i]=-1,vis[i]=0;
 36     dis[s]=pre[s]=0;
 37     flow[s]=inf;
 38     Q.push(s);
 39     while(!Q.empty()){
 40         int x=Q.front();
 41         Q.pop();
 42         vis[x]=0;
 43         for(int i=hl[x];i;i=e[i].ne){
 44             int v=e[i].v,c=e[i].c,w=e[i].f;
 45             if(c&&dis[v]>dis[x]+w){
 46                 dis[v]=dis[x]+w;
 47                 pre[v]=x;
 48                 id[v]=i;
 49                 flow[v]=min(flow[x],c);
 50                 if(!vis[v]){
 51                     vis[v]=1;
 52                     Q.push(v);
 53                 }
 54             }
 55         }
 56     }
 57     return dis[t]<inf;
 58 }
 59 int KM()
 60 {
 61     int ret(0);
 62     while(bfs()){
 63         tot++;
 64         if(tot>k) break;
 65         int now=t;
 66         while(now!=s){
 67             int i=id[now],j=e[i].ctr;
 68             e[i].c-=flow[t];
 69             e[j].c+=flow[t];
 70             now=pre[now];
 71         }
 72         ret+=flow[t]*dis[t];
 73     }
 74     return ret;
 75 }
 76 int main()
 77 {
 78     int w;
 79     scanf("%d%d",&n,&k);
 80     for(int i=1;i<=n;++i) 
 81         for(int j=1;j<=n;++j){
 82             scanf("%d",&w);
 83             add(cal(i,j),n*n+cal(i,j),1,-w,1);
 84             add(n*n+cal(i,j),cal(i,j),0,w,-1);
 85         }
 86     puts("");
 87     for(int i=1;i<=n;++i)
 88         for(int j=1;j<=n;++j){
 89             if(j+1<=n){
 90                 add(cal(i,j),cal(i,j+1),inf,0,1);
 91                 add(cal(i,j+1),cal(i,j),0,0,-1);
 92                 add(n*n+cal(i,j),cal(i,j+1),1,0,1);
 93                 add(cal(i,j+1),n*n+cal(i,j),0,0,-1);
 94             }
 95             if(i+1<=n){
 96                 add(cal(i,j),cal(i+1,j),inf,0,1);
 97                 add(cal(i+1,j),cal(i,j),0,0,-1);
 98                 add(n*n+cal(i,j),cal(i+1,j),1,0,1);
 99                 add(cal(i+1,j),n*n+cal(i,j),0,0,-1);
100             }
101         }
102     s=0,t=n*n*2+1;
103     add(0,1,inf,0,1);add(1,0,0,0,-1);
104     add(n*n,t,inf,0,1);add(t,n*n,0,0,-1);
105     add(t-1,t,inf,0,1);add(t,t-1,0,0,-1);
106     printf("%d
",-KM());
107     return 0;
108 }
原文地址:https://www.cnblogs.com/12mango/p/7718309.html