对每个piece一遍BFS求出到每个格子的距离。然后问题就相当于为每个piece选一个格子使得距离之和最大,且格子不能重复选。
可以想到费用流模型,每个piece和每个格子一个点,对于piece x和格子y,若x可移动到y,设x能到的最远距离为d,而x到y的距离为dis,那么就连边x->y,流量1,费用d - dis。最后连s和所有piece,所有格子和t,均为流量1费用0,跑最小费用最大流。
答案就是所有 d 的和减去最小费用。
const int N=105;
int n,m,a,res;
char S[N][N];
queue<int>qx,qy;
int d[N][N];
const int dx[ ]={1,0};
const int dy[ ]={0,1};
vector<int>E[N];
struct ex{int num,next,w,c;}map[100*50*50*2+1005];
int head[100+50*50+105],len=1;
inline void link(int x,int y,int w,int c)
{
len++;map[len].num=y;map[len].next=head[x];map[len].w=w;map[len].c=c;head[x]=len;
len++;map[len].num=x;map[len].next=head[y];map[len].w=0;map[len].c=-c;head[y]=len;
}
void BFS(int x,int y)
{
int i,j,xx,yy,mx=1;
qx.push(x);qy.push(y);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
d[i][j]=0;
d[x][y]=1;
while(!qx.empty( ))
{
x=qx.front( );qx.pop( );
y=qy.front( );qy.pop( );
for(i=0;i<=1;i++)
{
xx=x+dx[i];
yy=y+dy[i];
if(xx>n||yy>m||S[xx][yy]=='#'||d[xx][yy]) continue;
d[xx][yy]=d[x][y]+1;
mx=max(mx,d[xx][yy]);
qx.push(xx);
qy.push(yy);
}
}
res+=mx;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(d[i][j]) link(a,100+(i-1)*m+j,1,mx-d[i][j]+1);
}
const int DN = 100+50*50+105;
int s,t,ans,dis[DN],pr[DN];
bool in[DN];
queue<int>q;
const int orz=1e9;
bool SPFA( )
{
int i,x,y,c,w;
for(i=1;i<=t;i++) dis[i]=orz;
q.push(s);
while(!q.empty( ))
{
x=q.front( );q.pop( );in[x]=0;
for(i=head[x];i;i=map[i].next)
if(map[i].w)
{
y=map[i].num;c=map[i].c;
if(dis[y]>dis[x]+c)
{
dis[y]=dis[x]+c;pr[y]=i;
if(!in[y]) in[y]=1,q.push(y);
}
}
}
if(dis[t]==orz) return 0;
for(w=orz,i=t;i!=s;i=map[x^1].num) x=pr[i],w=min(w,map[x].w);
for(i=t;i!=s;i=map[x^1].num) x=pr[i],map[x].w-=w,map[x^1].w+=w;
ans+=dis[t]*w;
return 1;
}
int main( )
{
int i,j;
read(n);read(m);
for(i=1;i<=n;i++) scanf("%s",S[i]+1);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
if(S[i][j]=='o')
{
a++;
BFS(i,j);
}
}
s=0;
t=100+n*m+1;
for(i=1;i<=a;i++) link(s,i,1,0);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
link(100+(i-1)*m+j,t,1,0);
while(SPFA( ));
printf("%d",res-ans);
return 0;
}