题意:给你一个n*n(1<= n <= 50)的矩阵,每一个格子里面有一个值m[i][j]。假设第i行第j列的坐标为(i,j),那么点(i,j)只能走到点(i+1,j)和点(i,j+1),即只能向右和向下走。问从点(1,1)到点(n,n)走K次能够获得的最大值,每一个格子只有在第一次走过的时候总值才会加。
题解:将每个格子看成一个点A,然后把这个点A拆成两个点A和A'。如果点B在点A的右侧或下侧,那么点A'就与点B连一条费用为0,容量为无穷大的边。对于每两个点A和A',点A向点A'连一条费用为点A这个格子的值、容量为1的边和一条费用为0,容量为无穷大的边。再建立一个源点S。S与点C(1,1)连一条费用为0,容量为K的边,汇点定为点D'(n,n).然后可以求从点S到点D'(n,n)的最大费用最大流。(ps:拆点真难懂- -……………………)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cctype>
using namespace std;
#define INF 200000
#define Min(a,b) (a)<(b)? a:b
struct node{
int u;
int v;
int fei;
int cap;
int next;
};
node e[100005];
int m[55][55],edge_cnt,max_flow,min_cost;
int head[5005];
void add(int u,int v,int f,int c)
{
e[edge_cnt].u=u,e[edge_cnt].v=v,e[edge_cnt].fei=f,e[edge_cnt].cap=c;
e[edge_cnt].next=head[u],head[u]=edge_cnt;
edge_cnt++;
}
void cost_flow(int beg,int End)
{
int pre[5005],dist[5005],flag[5005];
while(1)
{
memset(pre,-1,sizeof(pre));
memset(flag,0,sizeof(flag));
memset(dist,0x3f,sizeof(dist));
queue<int>q;
q.push(beg);
dist[beg]=0;
while(!q.empty())
{
int t=q.front();
q.pop();
flag[t]=0;
for(int i=head[t];i!=-1;i=e[i].next)
{
if(e[i].cap>0&&dist[t]+e[i].fei<dist[e[i].v])
{
dist[e[i].v]= dist[t]+e[i].fei;
pre[e[i].v]=i;
if(!flag[e[i].v])
{
flag[e[i].v]=1;
q.push(e[i].v);
}
}
}
}
if(pre[End]==-1)
break;
int MIN=INF;
for(int i=End;pre[i]!=-1;i=e[pre[i]].u)
MIN=Min(MIN,e[pre[i]].cap);
for(int i=End;pre[i]!=-1;i=e[pre[i]].u)
{
e[pre[i]].cap-=MIN;
e[pre[i]^1].cap+=MIN;
}
max_flow+=MIN;
min_cost+=MIN*dist[End];
}
}
int main()
{
int n,k,s,t;
while(~scanf("%d%d",&n,&k))
{
memset(head,-1,sizeof(head));
edge_cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&m[i][j]);
//s=n*n*2;
//t=s+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int p1=(i-1)*n+j;
int p2=(i-1)*n+j+n*n;
add(p1,p2,-m[i][j],1);
add(p2,p1,m[i][j],1);
add(p1,p2,0,k);
add(p2,p1,0,0);
if(i<n)
{
int p1=(i-1)*n+j;
int p2=i*n+j;
add(p1+n*n,p2,0,k);
add(p2,p1+n*n,0,0);
}
if(j<n)
{
int p1=(i-1)*n+j;
int p2=(i-1)*n+j+1;
add(p1+n*n,p2,0,k);
add(p2,p1+n*n,0,0);
}
}
}
/*
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int b=(i-1)*n+j-1;
add(b*2,b*2+1,-m[i][j],1);
add(b*2+1,b*2,m[i][j],1);
add(b*2,b*2+1,0,k-1);
add(b*2+1,b*2,0,0);
}
for(int i=1;i<=n;i++)
for(int j=1;j<n;j++)
{
int b=(i-1)*n+j-1;
add(b*2+1,2*(b+1),0,k);
add(2*(b+1),b*2+1,0,0);
}
for(int i=1;i<n;i++)
for(int j=1;j<=n;j++)
{
int b=(i-1)*n+j-1;
add(b*2+1,2*(b+n),0,k);
add(2*(b+n),b*2+1,0,0);
}
*/
add(0,1,0,k);
add(1,0,0,0);
add(n*n*2,n*n*2+1,0,k);
add(n*n*2+1,n*n*2,0,0);
max_flow=min_cost=0;
cost_flow(0,2*n*n+1);
printf("%d\n",-min_cost);
}
return 0;
}