P2045 方格取数加强版 题解

题目描述

给出一个(N imes N)的矩阵,每一格有一个非负整数(a[i][j])每次走过时可以取出这个数,走过多次只算一次,求走(k)次取得的最大代价

问题求解

如果(k=1)的话,显然可以用(DP)来解决,但是(k>1)时前一种的走法对下一次产生了影响,所以考虑用网络流来做

把每个点看成是一个入点和一个出点,每个格子,我们可以从入点到出点建一条流量为(1),费用为(a[i][j])的边,和(k-1)条流量为(k-1),费用为(0)的边,表示一个数的代价只算一次,为了保证图的连通性,讲(i,j)向边上建流量为(k),费用为(0)的边

最后答案就是从((1,1))的入点到((n,n))的出点的最大流

代码实现

#include<bits/stdc++.h>
using namespace std;
const int maxn=5010,maxe=maxn*8,INF=0x3f3f3f3f;
int N,K,mp[55][55],T;
int lnk[maxn],nxt[maxe],son[maxe],w[maxe],cost[maxe],cnt=1,vis[maxn],cur[maxn],Q[maxn],dis[maxn];
int maxflow,mincost,st,ed;
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
void add_e(int x,int y,int z,int c){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;w[cnt]=z;cost[cnt]=c;}
void add_edge(int x,int y,int z,int c){add_e(x,y,z,c);add_e(y,x,0,-c);}
inline int calc(int x,int y){return N*(x-1)+y;}
int spfa(){
	int hed=0,til=1;Q[til]=st;
	memset(dis,INF,sizeof dis);dis[st]=0;
	while(hed!=til){
		hed=(hed+1)%maxn;vis[Q[hed]]=0;
		for(int j=lnk[Q[hed]];j;j=nxt[j]){
			if(w[j]>0&&dis[son[j]]>dis[Q[hed]]+cost[j]){
				dis[son[j]]=dis[Q[hed]]+cost[j];
				if(!vis[son[j]]){
					vis[son[j]]=1;Q[til=(til+1)%maxn]=son[j];
				}
			}
		}
	}
	return dis[ed]!=INF;
}
int DFS(int x,int delta){
	if(x==ed)return delta;
	int flow=0;vis[x]=1;
	for(int j=cur[x];j;j=nxt[j]){
		if(!vis[son[j]]&&w[j]&&dis[son[j]]==dis[x]+cost[j]){
			cur[x]=j;
			int t=DFS(son[j],min(delta-flow,w[j]));
			flow+=t;w[j]-=t;w[j^1]+=t;mincost+=t*cost[j];
			if(flow==delta)break;
		}
	}
	vis[x]=0;
	return flow;
}
void Dinic(){
	while(spfa()){
		memcpy(cur,lnk,sizeof cur);
		int tmp=DFS(st,INF);
		if(!tmp)break;
		maxflow+=tmp;
	}
}
int main(){
	N=read();K=read();T=N*N;
	for(int i=1;i<=N;i++)for(int j=1;j<=N;j++)mp[i][j]=read();
	st=1;ed=2*T;
	for(int i=1;i<=N;i++)
	for(int j=1;j<=N;j++){
		add_edge(calc(i,j),calc(i,j)+T,1,-mp[i][j]);
		add_edge(calc(i,j),calc(i,j)+T,K-1,0);
		if(i<N)add_edge(calc(i,j)+T,calc(i+1,j),K,0);
		if(j<N)add_edge(calc(i,j)+T,calc(i,j+1),K,0);
	}
	Dinic();
	printf("%d
",-mincost);
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/15184893.html