1 条题解
-
0
自动搬运
来自洛谷,原作者为

William2022
**搬运于
2025-08-24 23:02:45,当前版本为作者最后更新于2025-06-23 12:08:15,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Going Home 题解
题目大意
在一个 的地图上,存在等量的人和房子,一个人走到一个房子的代价为他们的曼哈顿距离。
我们需要安排人与房子的对应关系,使得总代价最小。
样例分析
HH..m ..... ..... ..... mm..H按照题目画出的图走就是最优方法。

思考
注意到:
- 每一个人都要找到房子,每一个房子都要找到人,是匹配问题
- 匹配时候不同的对应关系有不同的代价
根据第一条,想到网络流进行匹配,考虑到第二条,应当使用费用流。
图论建模
人和房子是对应的,网络流建立如下:
- 每个人作为源点,仅能流出 的流量
- 每个房子作为汇点,仅能接受 的流量
而对于每个人都可以选择每个房子,所以对于每一个人,连接到每一个房子,费用为他们之间的曼哈顿距离。
跑最小费用最大流。程序设计
- 一个超级源点,对每一个人指向一条流量为 ,费用为 的边
- 一个超级汇点,所有房子对其指向一条流量为 ,费用为 的边
- 枚举每一个人,对每个房子指向一条费用为他们之间曼哈顿距离的边
- 答案即为最大流的最小费用
代码
#include<bits/stdc++.h> typedef long long ll; const int E=25e6+10; const int V=1e4+10; int n,m; struct pair{int x,y,id;};//这里的id指这个人或者房子在图中的编号 struct Star{int to,w,c,nxt;}; Star e[E*2]; int hd[V],star=1; void addEdge(int u,int v,int w,int c){ star++; e[star]={v,w,c,hd[u]}; hd[u]=star; } void CostFlow(int u,int v,int w,int c){//建立流量边 addEdge(u,v,w,c); addEdge(v,u,0,-c); } const int S=1,T=2;//超级源点,超级汇点 int cnt=2;//往后开点 int Distance(const pair &a,const pair &b){ return abs(a.x-b.x)+abs(a.y-b.y); } int dis[V],pre[V]; bool SPFA(){ std::bitset<V> in; std::queue<int> q; memset(dis,0x3f,sizeof(dis)); q.push(S); dis[S]=0; in[S]=1; while(!q.empty()){ int u=q.front();q.pop(); in[u]=0; for(int id=hd[u];id;id=e[id].nxt){ int v=e[id].to,w=e[id].w,c=e[id].c; if(!w)continue; if(dis[u]+c<dis[v]){ pre[v]=id; dis[v]=dis[u]+c; if(!in[v]){ q.push(v); in[v]=1; } } } } return (dis[T]<(int)(1e9));// 能否到达汇点 } ll SSP(){//最小费用最大流 ssp ll ans=0; while(SPFA()){ ans+=dis[T]; for(int u=T;u!=S;u=e[pre[u]^1].to){ e[pre[u]].w=0; e[pre[u]^1].w=1; } } return ans; } ll solve(){ star=1; memset(hd,0,sizeof(hd)); //输入 std::vector<pair> H,M;//分别代表人和房子出现的位置 for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ char c; std::cin>>c; if(c=='H')H.push_back({i,j,++cnt}); else if(c=='m')M.push_back({i,j,++cnt}); } } //图论建模 for(pair p:H)CostFlow(S,p.id,1,0); for(pair p:M)CostFlow(p.id,T,1,0); for(pair a:H){ for(pair b:M){ CostFlow(a.id,b.id,1,Distance(a,b)); } } //最小费用最大流 return SSP(); } signed main(){ std::ios::sync_with_stdio(0);std::cout.tie(0);std::cin.tie(0); while(std::cin>>n>>m){ if(!n)break; std::cout<<solve()<<"\n"; } }
- 1
信息
- ID
- 10140
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者