分析:
网络流比较好的题
每个点拆成A和B两点
然后按照如图所示,每个点的A点向另一点的B点连边
最后如果那个点必须选,则不连从A到B的边(那条边表示这个点不加入最终方案)
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 100010
#define INF 0x3f3f3f3f
using namespace std;
vector<int> a[MAXN],w[MAXN],p[MAXN],rev[MAXN];
void add_edge(int u,int v,int len,int pri){
// PF("[%d %d %d %d]\n",u,v,len,pri);
a[u].push_back(v),a[v].push_back(u);
w[u].push_back(len),w[v].push_back(0);
p[u].push_back(pri),p[v].push_back(-pri);
rev[u].push_back(a[v].size()-1),rev[v].push_back(a[u].size()-1);
}
int las[MAXN],lasid[MAXN];
int dist[MAXN];
int s,t;
bool inq[MAXN];
queue<int> q;
bool spfa(){
memset(dist,0x3f3f3f3f,sizeof dist);
q.push(s);
dist[s]=0;
while(!q.empty()){
int x=q.front();
q.pop();
inq[x]=0;
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(w[x][i])
if(dist[u]>dist[x]+p[x][i]){
dist[u]=dist[x]+p[x][i];
las[u]=x;
lasid[u]=i;
if(inq[u]==0){
q.push(u);
inq[u]=1;
}
}
}
}
// PF("[%d]",dist[t]);
return dist[t]<0x3f3f3f3f;
}
pair<int,int> maxf(){
pair<int,int> res=make_pair(0,0);
while(spfa()){
int f=INF;
for(int i=t;i!=s;i=las[i])
f=min(w[las[i]][lasid[i]],f);
for(int i=t;i!=s;i=las[i]){
res.second+=f*p[las[i]][lasid[i]];
w[las[i]][lasid[i]]-=f;
w[i][rev[las[i]][lasid[i]]]+=f;
}
res.first+=f;
}
// PF("[%d %d]\n",res.first,res.second);
return res;
}
int C,R,tot;
bool used[MAXN];
int main(){
int T;
SF("%d",&T);
while(T--){
int n,m;
SF("%d%d",&n,&m);
s=n*m*2;
t=s+1;
tot=t+1;
for(int i=0;i<tot;i++)
a[i].clear(),rev[i].clear(),w[i].clear(),p[i].clear();
for(int i=0;i<n;i++)
for(int j=0;j<m-1;j++){
SF("%d",&C);
if((i^j)&1)
add_edge(i*m+j,i*m+j+1+n*m,1,-C);
else
add_edge(i*m+j+1,i*m+j+n*m,1,-C);
}
for(int i=0;i<n-1;i++)
for(int j=0;j<m;j++){
SF("%d",&R);
if((i^j)&1)
add_edge((i+1)*m+j,i*m+j+n*m,1,-R);
else
add_edge(i*m+j,(i+1)*m+j+n*m,1,-R);
}
int k,x,y;
SF("%d",&k);
memset(used,0,sizeof used);
for(int i=0;i<k;i++){
SF("%d%d",&x,&y);
x--,y--;
used[x*m+y]=1;
}
for(int i=0;i<n*m;i++){
add_edge(s,i,1,0);
add_edge(i+n*m,t,1,0);
if(used[i]==0)
add_edge(i,i+n*m,1,0);
}
pair<int,int> res=maxf();
if(res.first!=n*m)
PF("Impossible\n");
else
PF("%d\n",-res.second);
}
}