问题可以转化为二分图匹配来做。利用BFS求得每个X到每个B的最短距离,为权值。
然后用KM算法求最小权。需要用求最大权的算法,权值取反。
不存在无解的情况。
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <map> #include <algorithm> #define ll long long #define INF 2139062143 #define inf -2139062144 #define MOD 20071027 #define MAXN 100 using namespace std; bool visx[MAXN],visy[MAXN]; int lx[MAXN],ly[MAXN],w[MAXN][MAXN],slack[MAXN]; int link[MAXN]; int nx,ny; bool find(int x) { visx[x]=true; for(int y=1; y<=ny; ++y) if(!visy[y]) { int t=lx[x]+ly[y]-w[x][y]; if(t==0) { visy[y]=true; if(link[y]==-1||find(link[y])) { link[y]=x; return true; } } else slack[y]=min(slack[y],t); } return false; } int KM() { memset(link,-1,sizeof(link)); memset(lx,0x80,sizeof(lx)); memset(ly,0,sizeof(ly)); for(int i=1; i<=nx; ++i) for(int j=1; j<=ny; ++j) lx[i]=max(lx[i],w[i][j]); for(int x=1; x<=nx; ++x) { memset(slack,0x7f,sizeof(slack)); while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(find(x)) break; int d=INF; for(int y=1; y<=ny; ++y) if(!visy[y]&&d>slack[y]) d=slack[y]; for(int i=1; i<=nx; ++i) if(visx[i]) lx[i]-=d; for(int i=1; i<=ny; ++i) if(visy[i]) ly[i]+=d; else slack[i]-=d; } } int res=0; for(int i=1; i<=ny; ++i) if(link[i]!=-1) res+=w[link[i]][i]; return res; } char grid[MAXN][MAXN]; int flag[MAXN][MAXN]; int mx,my; struct Point { int x,y,s; }; int M[4][2]= {{1,0},{-1,0},{0,1},{0,-1}}; int BFS(int sx,int sy) { queue<Point> que; bool vis[MAXN][MAXN]= {0}; vis[sx][sy]=true; que.push(Point {sx,sy,0}); int u=flag[sx][sy]; while(!que.empty()) { Point q=que.front(); if(grid[q.x][q.y]=='B') w[u][flag[q.x][q.y]]=min(w[u][flag[q.x][q.y]],q.s); que.pop(); for(int i=0; i<4; ++i) { int ex=q.x+M[i][0],ey=q.y+M[i][1]; if(ex<1||ey<1||ex>mx||ey>my) continue; if(vis[ex][ey]||grid[ex][ey]=='#') continue; vis[ex][ey]=true; que.push(Point {ex,ey,q.s+1}); } } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&mx,&my); for(int i=1; i<=mx; ++i) scanf("%s",grid[i]+1); nx=ny=0; memset(flag,0,sizeof(flag)); for(int i=1; i<=mx; ++i) for(int j=1; grid[i][j]; ++j) if(grid[i][j]=='B') flag[i][j]=++ny; else if(grid[i][j]=='X') flag[i][j]=++nx; memset(w,0x7f,sizeof(w)); for(int i=1; i<=mx; ++i) for(int j=1; grid[i][j]; ++j) if(grid[i][j]=='X') BFS(i,j); for(int i=1; i<=nx; ++i) for(int j=1; j<=ny; ++j) w[i][j]=-w[i][j]; int res=KM(); printf("%d\n",-res); } return 0; }