这种棋盘模型很像网络流
但是边很难建。
可以动态加边,每次跑完一边费用流,把流过的边重新建一条,加上费用就好了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N=10010;
int n,q,nx,ny,S,T,cnt=1,lst,G[N],ans[N],vis[N];
int l[55][55],r[55][55];
char a[55][55];
struct edge{
int t,nx,f,w;
}E[N<<1];
inline void addedge(int x,int y,int f,int w){
E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].f=f; E[cnt].w=w; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].f=0; E[cnt].w=-w; G[y]=cnt;
}
queue<int> Q;
int frm[N],dis[N],chs[N];
inline void spfa(){
for(int i=0;i<=T;i++) dis[i]=1<<30,vis[i]=0;
vis[S]=1; dis[S]=0; Q.push(S);
while(!Q.empty()){
int x=Q.front(); Q.pop(); vis[x]=0;
for(int i=G[x];i;i=E[i].nx)
if(E[i].f && dis[E[i].t]>dis[x]+E[i].w){
dis[E[i].t]=dis[x]+E[i].w; frm[E[i].t]=i;
if(!vis[E[i].t]) Q.push(E[i].t),vis[E[i].t]=1;
}
}
int mf=1<<30;
for(int i=T;i;i=E[frm[i]^1].t) mf=min(mf,E[frm[i]].f);
++lst; ans[lst]=ans[lst-1]+dis[T]*mf;
for(int i=T;i;i=E[frm[i]^1].t){
E[frm[i]].f-=mf; E[frm[i]^1].f+=mf;
if(i==T) continue;
chs[i]++;
if(i<=nx) addedge(S,i,1,chs[i]); else addedge(i,T,1,chs[i]);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",a[i]+1);
for(int j=1;j<=n;j++){
l[i][j]=l[i][j-1];
if(a[i][j]=='.' && a[i][j-1]!='.') l[i][j]=++nx;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
r[j][i]=r[j-1][i];
if(a[j][i]=='.' && a[j-1][i]!='.') r[j][i]=++ny;
}
}
S=0; T=nx+ny+1;
for(int i=1;i<=nx;i++) addedge(S,i,1,0);
for(int i=1;i<=ny;i++) addedge(nx+i,T,1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]=='.') addedge(l[i][j],nx+r[i][j],1,0);
scanf("%d",&q);
while(q--){
int x; scanf("%d",&x);
while(lst<x)
spfa();
printf("%d\n",ans[x]);
}
return 0;
}