本人是用最小费用最大流变形过的,关于最小费用最大流可参考博客:
https://blog.csdn.net/LeYOUNGER/article/details/70156905 (算法证明)
https://blog.csdn.net/y990041769/article/details/40074527 (模板)
150+MS过,在讨论中看到有人用KM算法(一种处理关于二分图在完备匹配下的最大带权匹配的算法),粘贴代码之后交了,0MS过,说明KM算法处理这类问题时还是有优势的,日后找个时间学学。
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=2e2+10;
const int maxm=1e5+10;
const int inf=0x3f3f3f3f;
int map[maxn][maxn],head[maxn],cnt;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}},N,M,num;
struct edge
{
int from,to,cap,cost,next;
}e[maxm];
struct block
{
int id,x,y,mov;
block(int id,int x,int y,int mov){ this->id=id; this->x=x; this->y=y; this->mov=mov; };
};
struct MCMF
{
int s,t,flow,cost;
int dis[maxn],pre[maxn],a[maxn];
bool inq[maxn];
bool Bellman_Ford()
{
for(int i=0;i<=t;i++) dis[i]=inf;
mem(inq,0);
dis[s]=0; inq[s]=1; a[s]=inf; pre[s]=0;
queue<int> Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=0;
for(int i=head[u]; i ; i=e[i].next)
{
if(e[i].cap&&dis[e[i].to]>dis[u]+e[i].cost)
{
dis[e[i].to]=dis[u]+e[i].cost;
pre[e[i].to]=i;
a[e[i].to]=min(a[u],e[i].cap);
if(!inq[e[i].to])
{
Q.push(e[i].to);
inq[e[i].to]=1;
}
}
}
}
if(dis[t]==inf) return 0;
flow+=a[t];
cost+=dis[t]*a[t];
int u=t;
while(u!=s)
{
e[pre[u]].cap-=a[t];
e[pre[u]^1].cap+=a[t];
u=e[pre[u]].from;
}
return 1;
}
void mcmf()
{
flow=cost=0;
while(Bellman_Ford());
printf("%d\n",cost);
}
}m;
void addedge(int u,int v,int w,int c)
{
e[cnt].from=u; e[cnt].to=v; e[cnt].cap=w; e[cnt].cost=c; e[cnt].next=head[u]; head[u]=cnt++;
e[cnt].from=v; e[cnt].to=u; e[cnt].cap=0; e[cnt].cost=-c; e[cnt].next=head[v]; head[v]=cnt++;
}
void BFS(int id,int x,int y)
{
queue<block> Q;
int vis[maxn][maxn];
Q.push( block(id,x,y,0) );
for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) vis[i][j]=0;
vis[x][y]=1;
while(!Q.empty())
{
block fro=Q.front(); Q.pop();
if(fro.id>num)
{
addedge(id,fro.id,1,fro.mov);
}
for(int i=0;i<4;i++)
{
int x0=fro.x+dir[i][0],y0=fro.y+dir[i][1];
if(x0>=1&&x0<=N&&y0>=1&&y0<=M)
{
if(vis[x0][y0]) continue;
Q.push( block(map[x0][y0],x0,y0,fro.mov+1) );
vis[x0][y0]=1;
}
}
}
}
void init()
{
mem(head,0);
cnt=2;
for(int i=1;i<=num;i++)
addedge(0,i,1,0);
for(int i=num+1;i<=2*num;i++)
addedge(i,2*num+1,1,0);
m.s=0; m.t=2*num+1;
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
if(map[i][j]&&map[i][j]<=num)
BFS(map[i][j],i,j);
}
int main()
{
while(~scanf("%d%d",&N,&M))
{
if(!N&&!M) break;
num=0;
int k1,k2;
for(int i=1;i<=N;i++)
{
char s[maxn];
scanf("%s",s);
for(int j=0;j<M;j++)
{
if(s[j]=='H')
map[i][j+1]=2;
else if(s[j]=='m')
{
map[i][j+1]=1;
num++;
}
else map[i][j+1]=0;
}
}
k1=1; k2=num+1;
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
if(map[i][j]==2)
map[i][j]=k2++;
else if(map[i][j]==1)
map[i][j]=k1++;
init();
m.mcmf();
}
return 0;
}