题目大意:有个n*n的矩阵每个位置上有个权值,可以有K次从左上角到右下角,但每经过一次,该位置上的权值变为0,求经过的路程中最大的路权值。
思路:我们可以用费用流解决,经过K次的问题我们可以,在源点和汇点建立的时候,流量设为k即可。将每个点拆成两个并在两点中建立两条边,原因是为了控制每个位置上的数只能够取一次我们建立流量为1,费用为该位置的权值,并且可以经过此点若干次,那么就是另外一条边的作用了,就是流量值为inf,费用为0,然后经过画图分析可得,我们可以建立当前点和其右边和下边的点相连接(注意控制边界)。
因为我们是求得最大费用,所以建图的时候费用为负值,然后就是计算maxcost的时候不停相减即可。
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<queue> #include<cmath> #include<algorithm> #define MAX 1000 #define inf 0x3f3f3f3f using namespace std; int a[64][64],head[50000],cnt,cur[50000],star,en,flow,f[50000],qu[200000],cost,maxcost,dis[50000]; bool vis[50000]; struct node{ int to,w,c,next; }q[50000]; void bu(int a,int b,int w,int c){ q[cnt].to=b; q[cnt].w=w; q[cnt].c=c; q[cnt].next=head[a]; head[a]=cnt++; q[cnt].to=a; q[cnt].w=0; q[cnt].c=-c; q[cnt].next=head[b]; head[b]=cnt++; } bool SPFA(){ int f1,f2; memset(dis,inf,sizeof(dis)); f1=f2=0; qu[f1++]=star; vis[star]=true; f[star]=inf; cur[star]=-1; dis[star]=0; while(f1>=f2){ int u=qu[f2++]; vis[u]=false; for(int i=head[u];~i;i=q[i].next){ int v=q[i].to; if(dis[v]>dis[u]+q[i].c&&q[i].w>0){ dis[v]=dis[u]+q[i].c; cur[v]=i; f[v]=min(f[u],q[i].w); if(!vis[v]){ vis[v]=true; qu[f1++]=v; } } } } if(dis[en]>=inf) return false; flow+=f[en]; maxcost-=f[en]*dis[en]; for(int i=cur[en];~i;i=cur[q[i^1].to ]){ q[i].w-=f[en]; q[i^1].w+=f[en]; } return true; } int main(){ int n,m,i,j,k; while(~scanf("%d%d",&n,&k)){ maxcost=flow=cost=cnt=0; memset(head,-1,sizeof(head)); memset(vis,false,sizeof(vis)); for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ scanf("%d",&a[i][j]); } } en=2*n*n+1; star=0; bu(star,1,k,0); bu(2*n*n,en,k,0); for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ bu((i-1)*n+j,(i-1)*n+j+n*n,1,-a[i][j]); bu((i-1)*n+j,(i-1)*n+j+n*n,inf,0); if(j<n){ bu((i-1)*n+j+n*n,(i-1)*n+j+1,inf,0); } if(i<n){ bu((i-1)*n+j+n*n,i*n+j,inf,0 ); } } } while(SPFA()); printf("%d\n",maxcost); } return 0; }