题目描述:
n 个小人回到 n 间房子,要求一对一,告诉每个人的位置和每个房子的位置,问n个人移动的总距离最少是多少
题解:
最小权值匹配模板
我们分别记录人和房,然后人与房连边并记录边权
将所有边权值取相反数,然后跑一遍最优权值匹配模板
详细看代码,仔细看看怎么构造图
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 300 + 10;
int sx[maxn], sy[maxn], vx[maxn], vy[maxn], match[maxn];
int money[maxn][maxn], slack[maxn];
int n;
int x,y;
bool dfs(int x)
{
vx[x] = true;
for(int i = 1; i <= n; i++)
{
int xx= sx[x] + sy[i] - money[x][i];
if(!vy[i] && !xx)
{
vy[i] = true;
if(match[i]==-1 || dfs(match[i]))
{
match[i] = x;
return true;
}
}
else if(slack[i] > xx)
slack[i] = xx;
}
return false;
}
void bestmatch()
{
for(int i = 1; i <= n; i++)
{
while(1)
{
memset(vx, false, sizeof(vx));
memset(vy, false, sizeof(vy));
memset(slack, 0x3f, sizeof(slack));
if(dfs(i))
break;
int dd = inf;
for(int i = 1; i <= n; i++)
if(!vy[i] && dd>slack[i])
dd = slack[i];
for(int i = 1; i <= n; i++)
{
if(vx[i])
sx[i] -= dd;
if(vy[i])
sy[i] += dd;
}
}
}
}
struct node{
int x,y;
}H[maxn],m[maxn];
int main()
{
while(~scanf("%d%d", &x,&y))
{
if(x==0&&y==0)break;
int tot1=0;
int tot2=0;
for(int i=1;i<=x;i++)
{
for(int j=1;j<=y;j++)
{
char x;
cin>>x;
if(x=='H')
{
H[++tot1].x=i;
H[tot1].y=j;
}
else if(x=='m')
{
m[++tot2].x=i;
m[tot2].y=j;
}
else continue;
}
}
memset(sy, 0, sizeof(sy));
for(int i=1;i<=tot1;i++)
{
for(int j=1;j<=tot2;j++)
{
money[i][j]=(abs(H[i].x-m[j].x)+abs(H[i].y-m[j].y))*(-1);
sx[i] = max(sx[i], money[i][j]);
}
}
n=tot1;
memset(match, -1, sizeof(match));
bestmatch();
int sum = 0;
for(int i = 1; i <= n; i++)
sum += money[match[i]][i];
printf("%d\n", sum*(-1));
}
return 0;
}
京公网安备 11010502036488号