题目描述
给出一个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
思路
拆点+最大流费用最大流
代码
#include<bits/stdc++.h> #define N 107000 #define M 107000 #define inf 1<<29 using namespace std; struct node{ int y,z,p,next; }e[M*2]; int tot=1,head[N],maxflow=0,ans=0,s,t; void add(int x,int y,int z,int p){ e[++tot].y=y;e[tot].z=z;e[tot].p=p; e[tot].next=head[x];head[x]=tot; } int incf[N],v[N],pre[N],d[N]; bool spfa(){ queue<int> q; memset(d,0xcf,sizeof(d)); memset(v,0,sizeof(v)); q.push(s);d[s]=0;v[s]=1; incf[s]=inf; while(q.size()){ int x=q.front();v[x]=0;q.pop(); for(int i=head[x];i;i=e[i].next){ int y=e[i].y,z=e[i].z; if(!z) continue; if(d[y]<d[x]+e[i].p){ d[y]=d[x]+e[i].p; incf[y]=min(incf[x],z); pre[y]=i; if(!v[y]) v[y]=1,q.push(y); } } } if(d[t]==0xcfcfcfcf) return false; return true; } void update(){ int x=t; while(x!=s){ int i=pre[x]; e[i].z-=incf[t]; e[i^1].z+=incf[t]; x=e[i^1].y; } maxflow+=incf[t]; ans+=d[t]*incf[t]; } int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } int f(int x,int y){ int k=x*x-y*y; int g=sqrt(k); if(g*g==k&&gcd(y,g)==1) return 1; else return 0; } int n,k; int num(int a,int b){ return (a-1)*n+b; } int a[60][60]; #define MAXN 3000 int main(){ cin>>n>>k; s=num(1,1);t=num(n,n)+MAXN; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ add(num(i,j),num(i,j)+MAXN,1,a[i][j]);add(num(i,j)+MAXN,num(i,j),0,-a[i][j]); add(num(i,j),num(i,j)+MAXN,k-1,0); add(num(i,j)+MAXN,num(i,j),0,0); if (i+1<=n) add(num(i,j)+MAXN,num(i+1,j),k,0),add(num(i+1,j),num(i,j)+MAXN,0,0); if (j+1<=n) add(num(i,j)+MAXN,num(i,j+1),k,0),add(num(i,j+1),num(i,j)+MAXN,0,0); } } while(spfa()) update(); cout<<ans<<endl; return 0; }