题目大概说有一个n×n的矩阵,每个格子都有权值和高度,在这个矩阵中进行最多k次旅行,每次旅行能从当前格子走到相邻且高度更小的格子,走到格子边界就能出去完成这次旅行。每走到一个格子就累加格子的权值然后把该格子的权值设置成0。问能获得的最大权和。
很容易建容量网络。。主要是每个点拆成两个点,中间的边再拆成两条,一条容量1费用-该边权值的边,另一条容量INF费用0的边。。
另外题目要求得是最多k次的旅行,实际上越多显然越好,所以最大流是没问题的。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 55*55*2
#define MAXM 55*55*2*55*55*4
struct Edge{
int u,v,cap,cost,next;
}edge[MAXM];
int vs,vt,NV,NE,head[MAXN];
void addEdge(int u,int v,int cap,int cost){
edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].u=v; edge[NE].v=u; edge[NE].cap=; edge[NE].cost=-cost;
edge[NE].next=head[v]; head[v]=NE++;
}
int d[MAXN],pre[MAXN];
bool vis[MAXN];
bool SPFA(){
for(int i=; i<NV; ++i){
d[i]=INF; vis[i]=;
}
d[vs]=; vis[vs]=;
queue<int> que;
que.push(vs);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap && d[v]>d[u]+edge[i].cost){
d[v]=d[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=;
que.push(v);
}
}
}
vis[u]=;
}
return d[vt]!=INF;
}
int MCMF(){
int res=;
while(SPFA()){
int flow=INF,cost=;
for(int u=vt; u!=vs; u=edge[pre[u]].u){
flow=min(flow,edge[pre[u]].cap);
}
for(int u=vt; u!=vs; u=edge[pre[u]].u){
edge[pre[u]].cap-=flow;
edge[pre[u]^].cap+=flow;
cost+=flow*edge[pre[u]].cost;
}
res+=cost;
}
return res;
}
int val[][],height[][];
int dx[]={,,,-};
int dy[]={,-,,};
int main(){
int t,n,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i=; i<n; ++i){
for(int j=; j<n; ++j) scanf("%d",&val[i][j]);
}
for(int i=; i<n; ++i){
for(int j=; j<n; ++j) scanf("%d",&height[i][j]);
}
int S=n*n*;
vs=n*n*+; vt=vs+; NV=vt+; NE=;
memset(head,-,sizeof(head));
addEdge(vs,S,k,);
for(int i=; i<n; ++i){
for(int j=; j<n; ++j){
addEdge(i*n+j,i*n+j+n*n,,-val[i][j]);
addEdge(i*n+j,i*n+j+n*n,INF,);
addEdge(S,i*n+j,INF,);
if(i== || j== || i==n- || j==n-) addEdge(i*n+j+n*n,vt,INF,);
for(int k=; k<; ++k){
int nx=i+dx[k],ny=j+dy[k];
if(nx< || nx>=n || ny< || ny>=n || height[i][j]<=height[nx][ny]) continue;
addEdge(i*n+j+n*n,nx*n+ny,INF,);
}
}
}
printf("%d\n",-MCMF());
}
return ;
}