题解:
考虑黑白染色,把原来的点拆为两个点,令黑点左右连边,白点上下连边做最大匹配。 如果不是必需点,则自己和自己连边。
显然任意合法方案都对应着一组匹配,而任意一组匹配都可以还原出一个方案。 我们做最大费用最大流即可。
#include <bits/stdc++.h>
using namespace std;
inline int rd(int x=0) {return (scanf("%d",&x),x);}
const int N=1e3+50,M=2e5+50,L=25,INF=0x3f3f3f3f;
int n,m,src,des,cx[L][L],cy[L][L],ms[L][L],gg; queue <int> q;
int g[N],nt[M],vt[M],c[M],w[M],ec,dis[M],vis[M],exi[M],vs,cur[N];
inline int id(int x,int y,int t) {return (x-1)*m+y+(t==2)*n*m;}
inline void init() {memset(g+1,0,sizeof(int)*des); ec=1; gg=0;}
inline void add(int x,int y,int cc,int ww) {
nt[++ec]=g[x]; g[x]=ec; vt[ec]=y; c[ec]=cc; w[ec]=ww;
nt[++ec]=g[y]; g[y]=ec; vt[ec]=x; c[ec]=0; w[ec]=-ww;
}
inline bool spfa() {
for(int i=1;i<=des;i++) dis[i]=-INF;
q.push(src); dis[src]=0;
while(!q.empty()) {
int u=q.front(); q.pop(); exi[u]=0;
for(int e=g[u];e;e=nt[e]) {
if(!c[e] || dis[vt[e]]>=dis[u]+w[e]) continue;
dis[vt[e]]=dis[u]+w[e]; if(!exi[vt[e]]) exi[vt[e]]=1, q.push(vt[e]);
}
} return dis[des]>-INF;
}
inline int dinic(int x,int f,int cost) {
if(x==des) {gg+=cost*f; return f;}
int rs=0; vis[x]=vs;
for(int &e=cur[x];e;e=nt[e]) {
if(!c[e] || vis[vt[e]]==vs || (dis[vt[e]]!=dis[x]+w[e])) continue;
int o=dinic(vt[e],min(f-rs,c[e]),cost+w[e]);
rs+=o; c[e]-=o; c[e^1]+=o;
if(rs==f) return rs;
} return dis[x]=-INF, rs;
}
inline int maxflow() {
int rs=0;
while(spfa()) {
int t; ++vs, memcpy(cur+1,g+1,sizeof(int)*des);
while((t=dinic(src,INF,0))) rs+=t, ++vs, memcpy(cur+1,g+1,sizeof(int)*des);
} return rs;
}
inline void solve() {
n=rd(), m=rd(), src=id(n,m,2)+1; des=src+1; init(); memset(ms,0,sizeof(ms));
for(int i=1;i<=n;i++) for(int j=1;j<m;j++) cx[i][j]=rd();
for(int i=1;i<n;i++) for(int j=1;j<=m;j++) cy[i][j]=rd();
for(int i=rd();i>=1;i--) {int x=rd(), y=rd(); ms[x][y]=1;}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {
if((i+j)&1) {
if(j>1) add(id(i,j,1),id(i,j-1,2),1,cx[i][j-1]);
if(j<m) add(id(i,j,1),id(i,j+1,2),1,cx[i][j]);
} else {
if(i>1) add(id(i,j,1),id(i-1,j,2),1,cy[i-1][j]);
if(i<n) add(id(i,j,1),id(i+1,j,2),1,cy[i][j]);
}
add(src,id(i,j,1),1,0); add(id(i,j,2),des,1,0);
if(!ms[i][j]) add(id(i,j,1),id(i,j,2),1,0);
}
static int tl=0; printf("Case #%d: ",++tl);
if(maxflow()==n*m) cout<<gg<<endl;
else cout<<"Impossible"<<endl;
}
int main() {
for(int i=rd();i;i--) solve();
}