HDU--1533--Going Home--KM算法
Going Home
Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point.
You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
2 10 28
#include <iostream>
#include <cstring>
#define MAX (1<<30)
#define MIN -MAX
using namespace std;
struct ssss
{
int x,y;
};
ssss s1[111],s2[111];
int n,m,l1,l2,map[111][111];
int rode[111],r[111];
bool vx[111],vy[111];
int sx[111],sy[111];
int dfs(int x)
{
vx[x]=1; //标记增广路左边已訪问的点
int i,j,k,l;
for(i=0;i<l2;i++)
if(!vy[i])
{
k=sx[x]+sy[i]-map[x][i];
if(k==0)
{
vy[i]=1;//訪问它再标记已訪问
if(rode[i]==-1||dfs(rode[i])) //假设右边的点没有匹配或者有匹配(继续用他的匹配点继续找)
{
rode[i]=x; //记录右边点匹配到的左边点的序号
return 1;
}
}else if(r[i]>k)r[i]=k; //记录右端点没訪问的边的最小差值。用来导入
}
return 0;
}
int Dinic()
{
int i,j,k,l;
memset(sy,0,sizeof(sy)); //标记右端点权值
memset(rode,-1,sizeof(rode)); //右端点匹配点初始化为-1
for(i=0;i<l1;i++)
{
sx[i]=MIN;
for(j=0;j<l2;j++)
sx[i]=max(sx[i],map[i][j]); //左端点权值取最大的边的值
}
for(i=0;i<l1;i++)
{
for(j=0;j<l2;j++)r[j]=MAX;
while(1)
{
memset(vx,0,sizeof(vx)); //訪问标记初始化
memset(vy,0,sizeof(vy));
if(dfs(i))break; //匹配到了就结束
k=MAX;
for(j=0;j<l2;j++)
if(!vy[j])k=min(k,r[j]); //不然导入差值最小的边(这是保证匹配的总值从最大逐渐减小)
for(j=0;j<l1;j++)
if(vx[j])sx[j]-=k; //左端点权值减小
for(j=0;j<l2;j++)
if(vy[j])sy[j]+=k; //右端点权值曾加
//这样导入了边之后其它匹配不变x+y=(x-k)+(y+k)
}
}
for(i=k=0;i<l2;i++)
k+=map[rode[i]][i];
return -k;
}
int bb(int x)
{
return x>0?x:-x;
}
int main (void)
{
int i,j,k,l;
char c;
while(cin>>n>>m&&n)
{
l1=l2=0;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
cin>>c;
if(c=='m')
{
s1[l1].x=i;
s1[l1].y=j;
l1++;
}
if(c=='H')
{
s2[l2].x=i;
s2[l2].y=j;
l2++;
}
}
for(i=0;i<l1;i++)
for(j=0;j<l2;j++)
{
k=bb(s1[i].x-s2[j].x)+bb(s1[i].y-s2[j].y);
map[i][j]=(k<0?k:-k);
}
cout<<Dinic()<<endl;
}
return 0;
}