看到题的第一想法:上下界最大费用循环流
后来问了下同学,发现可以如下表示:
每个格子拆成入和出,
假如这个格子没有限制必须走,那么它就可以不参与匹配,也就是匹配自己即可
对图黑白染色以决定是竖进横出还是横进竖出
向相邻格子匹配权为壁的代价
然后就变成了二分图最大权匹配
#include<stdio.h>
#include<cstring>
#include<queue>
using namespace std;
#define cint const int &
#define poi(x,y) ((x-1)*m+y)
#define Void inline void
#define N 35
#define M 2005
int s[M],tot,S,T,Q[M*20],ans,pt[M],st[M],tm[M],ts,dis[M],n,m,c[N][N],r[N][N];
bool w[N][N],vis[M];
inline int rd() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct edge{int v,c,w,n;}e[M<<4];
Void push(cint u,cint v,cint w)
{
e[++tot]=(edge){v,1,w,s[u]};s[u]=tot;
e[++tot]=(edge){u,0,-w,s[v]};s[v]=tot;
}
Void prepare()
{
S=0,T=1;tot=1;ans=0;
#define clean(a) memset(a,0,sizeof(a))
clean(s);
clean(w);
}
inline bool BFS()
{
tm[S]=++ts;
Q[1]=S;
for (int l=1,r=1;l<=r;l++)
{
vis[Q[l]]=0;
#define V e[i].v
for (int i=s[Q[l]];i;i=e[i].n) if (e[i].c && (tm[V]<ts || dis[V]<dis[Q[l]]+e[i].w))
{
if (tm[V]<ts) tm[V]=ts,vis[V]=0;
dis[V]=dis[st[V]=Q[l]]+e[pt[V]=i].w;
if (!vis[V]) vis[Q[++r]=V]=1;
}
}
if (tm[T]<ts) return 0;
for (int i=T;i!=S;i=st[i]) e[pt[i]].c=0,e[pt[i]^1].c=1;
ans+=dis[T];
return 1;
}
void solve()
{
prepare();
n=rd(),m=rd();
for (int i=1;i<=n;i++) for (int j=1;j<m;j++) c[i][j]=rd();
for (int i=1;i<n;i++) for (int j=1;j<=m;j++) r[i][j]=rd();
for (int k=rd(),u,v;k--;u=rd(),v=rd(),w[u][v]=1);
for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
{
int K=poi(i,j)<<1;
push(S,K|1,0);push(K,T,0);
if (!w[i][j]) push(K|1,K,0);
}
for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (i+j&1)
{
if (i<n) push(poi(i,j)<<1|1,poi(i+1,j)<<1,r[i][j]);
if (1<i) push(poi(i,j)<<1|1,poi(i-1,j)<<1,r[i-1][j]);
}
else
{
if (j<m) push(poi(i,j)<<1|1,poi(i,j+1)<<1,c[i][j]);
if (1<j) push(poi(i,j)<<1|1,poi(i,j-1)<<1,c[i][j-1]);
}
bool flag=1;
for (int i=1;i<=n*m;i++) if (!BFS()){flag=0;break;}
if (flag) printf("%d\n",ans);
else puts("Impossible");
}
main(){for (int T=rd(),i=1;i<=T;i++) printf("Case #%d: ",i),solve();}