题目链接
建图:
源点到人的费用为0容量为1;
每个人到每个房子建一条边,费用为这个房子到这个人的距离,容量为1;
房子到终点的费用为0容量为1;
做这个题时,找了半天bug,首先注意房子和人的个数不是n,误以为n,调错了好久,还有sum,num的初始化,一开始放错位置了,还有就是存房子和人的位置时,存错了;
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define M 1100
const int inf=0x3f3f3f3f;
int n,m;
struct node
{
int u,v,c,f,next; //C为花费,F为flow流量
} e[M*40];
struct point
{
int x,y;
} a[500],b[500];
int pre[M],dis[M],head[M],t;
int vis[M];
char mmap[500][500];
void add1(int u,int v,int c,int f)
{
e[t].u=u;
e[t].v=v;
e[t].c=c;
e[t].f=f;
e[t].next=head[u];
head[u]=t++;
}
void add(int u,int v,int c,int f)//费用,流量
{
add1(u,v,c,f);
add1(v,u,-c,0); //反向边流量初始为零,如果走反向边费用正好和原边抵消
}
int spfa(int s,int t)
{
int i,u,v;
queue<int>q;
q.push(s);
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(i=s; i<=t; i++)
dis[i]=inf;
dis[s]=0;
while(!q.empty())
{
u=q.front();
q.pop();
for(i=head[u]; i!=-1; i=e[i].next)
{
v=e[i].v;
if(e[i].f&&dis[v]>dis[u]+e[i].c) //找到一条最小费用流
{
dis[v]=dis[u]+e[i].c;
pre[v]=i; //记录路径
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
vis[u]=0;
}
if(dis[t]!=inf)
return 1;
return 0;
}
void solve(int s,int t)
{
int ans=0,i,j;
int flow=0,cost=0; //总流量、总费用
while(spfa(s,t))
{
int minf=inf;
for(i=pre[t]; i!=-1; i=pre[e[i].u])
{
if(e[i].f<minf)
minf=e[i].f;
}
flow+=minf; //该条路径的流量
for(i=pre[t]; i!=-1; i=pre[e[i].u])
{
j=i^1;
e[i].f-=minf;
e[j].f+=minf;
}
cost+=dis[t]*minf; //单位运费和乘以流量得费用
}
printf("%d\n",cost);
}
int main()
{
while(~scanf("%d%d",&n,&m)&&(n||m))
{
t=0;
int sum=1,num=1;
memset(head,-1,sizeof(head));
for(int i=1; i<=n; i++)
{
scanf("%s",mmap[i]+1);
}
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// {
// printf("%c",mmap[i][j]);
// }
// printf("\n");
// }
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(mmap[i][j]=='m')
{
a[sum].x=i;
a[sum].y=j;
sum++;
}
if(mmap[i][j]=='H')
{
b[num].x=i;
b[num].y=j;
num++;
}
}
}
int s=0,tt=sum-1+num-1+1;
for(int i=1; i<sum; i++) //i,人,j+n,房子
{
for(int j=1; j<num; j++)
{
int dis=abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y);
add(i,j+sum-1,dis,1);
}
}
for(int i=1; i<sum; i++)
{
add(s,i,0,1);
}
for(int i=1; i<num; i++)
{
add(i+sum-1,tt,0,1);
}
solve(s,tt);
}
}