C-Going Home_2022图论班第一章图匹配例题与习题 (nowcoder.com)
在网格地图上有n个小人和n座房子。在每个单位时间内,每个小人都可以水平或垂直地移动一个单位步到相邻点。对于每个小矮人,你需要为他每走一步支付1美元的旅费,直到他进入一所房子。这项任务很复杂,因为每栋房子只能容纳一个小人。
你的任务是计算出把这n个小人送到n个不同的房子里所需要支付的最小金额。输入是场景的映射,a '。'表示一个空的空间,'H'表示这一点上有一个房子,'m'表示这一点上有一个小人。
你可以把网格地图上的每个点想象成一个相当大的正方形,所以它可以同时容纳n个小人;此外,如果一个小人没有进入房子就踩在有房子的网格上也是可以的。
输入描述:
输入中有一个或多个测试用例。每种情况都以给出两个整数N和M的一行开始,其中N是映射的行数,M是列数。其余的输入将是N行描述映射的代码。你可以假设N和M都在2到100之间。地图上的“H”和“m”的数量是一样的;最多有100栋房子。N和M的输入将以0结束。
输出描述:
对于每个测试用例,输出一行包含单个整数的行,这是您需要支付的最小金额,以美元为单位。
题解:
首先把人的位置与房子位置存储
记录人到每一个房子的曼哈顿距离,
找到每个人的最大顶标,记得初始化房子的顶标为0
剩下就是KM的板子了
但是这道题是要我们求最小代价,所以我们记录距离时要变成相反数,这样求出的距离是最大的
最后输出- res就是最小代价
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
#define int long long
int n,m;
int p[105][2];
int h[105][2];
int a[105][105];
int link[105];
int lx[105],ly[105];
int x,y;
int vx[105],vy[105];
int dfs(int x)
{
vx[x] = 1;
for(int i = 1;i <= y;i++)
{
if(!vy[i]&&lx[x] + ly[i] == a[x][i])
{
vy[i] = 1;
if(!link[i] || dfs(link[i]))
{
link[i] = x;
return 1;
}
}
}
return 0;
}
int check()
{
memset(link,0,sizeof link);
memset(lx,0xf3,sizeof lx);
memset(ly,0,sizeof ly);
for(int i = 1;i <= x;i++)
{
for(int j = 1;j <= y;j++)
{
lx[i] = max(lx[i],a[i][j]);
}
}
for(int i = 1;i <= x;i++)
{
while(1)
{
memset(vx,0,sizeof vx);
memset(vy,0,sizeof vy);
if(dfs(i))
break;
int d = 0x3f;
for(int j = 1;j <= x;j++)
{
if(vx[j])
{
for(int k = 1;k <= y;k++)
{
if(!vy[k])
{
d = min(d,lx[j] + ly[k] - a[j][k]);
}
}
}
}
if(d == 0x3f)
return 0;
for(int j = 1;j <= x;j++)
if(vx[j])
lx[j] -= d;
for(int j = 1;j <= y;j++)
if(vy[j])
ly[j] += d;
}
}
return 1;
}
void solve()
{
x = 0,y = 0;
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
char o;
cin >> o;
if(o == 'H')
{
h[++y][0] = i;
h[y][1] = j;
}
if(o == 'm')
{
p[++x][0] = i;
p[x][1] = j;
}
}
}
for(int i = 1;i <= x;i++)
{
for(int j = 1;j <= y;j++)
{
a[i][j] = -(abs(p[i][0] - h[j][0]) + abs(p[i][1] - h[j][1]));
}
}
if(check())
{
int res = 0;
for(int i = 1;i <= y;i++)
{
res += a[link[i]][i];
}
cout << -res<<"\n";
}
}
//17 5
//
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int t = 1;
// cin >> t;
while(t)
{
cin >> n >> m;
if(!n&&!m)
break;
solve();
}
}