就是最基本的二分图最优匹配,将每个人向每个房子建一条边,权值就是他们manhattan距离。然后对所有权值取反,求一次最大二分图最优匹配,在将结果取反就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Maxn 110
using namespace std;
int n;//点的数目
int lx[Maxn],ly[Maxn]; //顶点标号
int weight[Maxn][Maxn];// 边的权值
int slack[Maxn];// Y(i)的松弛函数
int sx[Maxn],sy[Maxn]; //标记X,Y中的顶点是否在交错路径上
int match[Maxn];//Y的匹配
struct Point{
    int x,y;
}house[Maxn],man[Maxn];
int Dis(Point a,Point b)
{
    return abs(a.x-b.x)+abs(a.y-b.y);
}
int dfs(int u)
{
    sx[u]=1;
    int i;
    for(i=1;i<=n;i++)
    {
        if(!sy[i]&&lx[u]+ly[i]==weight[u][i])//如果在相等子图中,且未被访问
        {
            sy[i]=1;
            if(match[i]==-1||dfs(match[i]))
            {
                match[i]=u;
                return 1;
            }
        }
        else
        if(!sy[i])//Y(i)不在交错路径当中
            slack[i]=min(slack[i],lx[u]+ly[i]-weight[u][i]);
    }
    return 0;
}
int bestmatch(bool f)
{
    int i,j;
    if(!f)
    {
        for(i=1;i<=n;i++)
        {
            lx[i]=-0x7FFFFFFF;
            ly[i]=0;
            for(j=1;j<=n;j++)
            {
                weight[i][j]=-weight[i][j];
                lx[i]=max(lx[i],weight[i][j]);
            }
        }
    }
    else
    {
        for(i=1;i<=n;i++)
        {
            lx[i]=0;
            ly[i]=0;
            for(j=1;j<=n;j++)
                lx[i]=max(lx[i],weight[i][j]);
        }
    }
    memset(match,-1,sizeof(match));
    for(i=1;i<=n;i++)
    while(1)
    {
        memset(sx,0,sizeof(sx));
        memset(sy,0,sizeof(sy));
        for(j=0;j<=Maxn-1;j++)
            slack[j]=0x7FFFFFFF;
        if(dfs(i))
            break;
        int dx=0x7FFFFFFF;
        for(j=1;j<=n;j++)
            dx=min(dx,slack[j]);
        for(j=1;j<=n;j++)
        {
            if(sx[j])
                lx[j]-=dx;
            if(sy[j])
                ly[j]+=dx;
        }
    }
    int ans=0;
    for(i=1;i<=n;i++)
        ans+=weight[match[i]][i];
    if(!f)
        ans=-ans;
    return ans;
}
int main()
{
    int i,j,N,M,a,b;
    char str[110];
    while(scanf("%d%d",&N,&M),N||M)
    {
        a=b=0;
        for(i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(j=0;j<M;j++)
            {
                if(str[j]=='H')
                    house[++a].x=i,house[a].y=j;
                if(str[j]=='m')
                    man[++b].x=i,man[b].y=j;
            }
        }
        n=a;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
                weight[i][j]=Dis(man[i],house[j]);
        }
        printf("%d\n",bestmatch(false));
    }
    return 0;
}
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-17
  • 2022-12-23
  • 2022-01-13
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-04
  • 2022-01-03
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案