题意:

  一个矩阵n*m,其中有k个房子和k个人,k个人分别必须走到任意一个房子中(匹配),但是权值就是长度(非欧拉距离),求匹配完的权之和。

思路:

  建图方法是,首先将k个人和k个房子分别抽出来到集合X和Y中,计算两两之间的距离,X到Y有一条边,费用为正,容量为1;Y到X也有一条边,费用为负,容量为0(其实两条边就是相反的)。添加一个源点0号到X集,添加一个汇点2*k+1号到Y集,这些费用都是0,容量都是1。

  建完图就用正常的方法(EK+SPFA)来解决就行了。由于我想要让每次增广路只找到流为1的路径,所以我在2*k+1号点后面还加个点2*k+2,仅1条边,费用为0,容量为1。这样每次spfa至多也只有1流量通过到汇点了。(可不用此法,将每次spfa所得cost[end]*flow[end]就行了,因为可能流过的并不止1流量。)

  

 #include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define INF 0x7f7f7f7f
using namespace std;
const int N=+;
vector<int> vect[N];
int flow[N], cost[N], path[N], inq[N], edge_cnt;
struct node
{
int from;
int to;
int val;
int cap;
int flo;
}edge[N*];//边数要自己估计,不然就会RE void add_node(int from,int to, int val, int cap, int flo)
{
edge[edge_cnt].from=from;
edge[edge_cnt].to=to;
edge[edge_cnt].val=val;
edge[edge_cnt].cap=cap;
edge[edge_cnt].flo=flo;
vect[from].push_back(edge_cnt++);
} int spfa(int s,int e)
{
deque<int> que;
que.push_back(s);
inq[s]=;
flow[s]=INF;
cost[s]=; while(!que.empty())
{
int x=que.front();
que.pop_front();
inq[x]=;
for(int i=; i<vect[x].size(); i++)
{
node e=edge[vect[x][i]];
if(e.cap>e.flo && cost[e.to]>cost[e.from] + e.val)
{
cost[e.to]=cost[x]+ e.val;//每次的流最多只是1。
path[e.to]=vect[x][i];
flow[e.to]=min(flow[e.from], e.cap-e.flo);
if(!inq[e.to])
{
inq[e.to]=;
que.push_back(e.to);
}
}
}
}
return cost[e];
} int cal(int s,int e)
{
int ans=;
while(true)
{
memset(flow, , sizeof(flow));
memset(cost, 0x7f, sizeof(cost));
memset(path, , sizeof(path));
memset(inq, , sizeof(inq)); if(spfa(s,e)==INF) return ans;
ans+=cost[e]; int ed=e-;//连e点那条边不清空,可以保证每次至多1流。
while(ed!=s)
{
int t=path[ed];
edge[t].flo++;
edge[t^].flo--;
ed=edge[t].from;
}
}
} int main()
{
freopen("input.txt", "r", stdin);
int n, m;char ch;
while(~scanf("%d%d",&n,&m),n+m)
{
for(int i=N-; i>=; i--) vect[i].clear();
memset(edge, , sizeof(edge));
edge_cnt=;
int cnt=;
vector<pii> vect_h,vect_m; for(int i=; i<=n; i++)
for(int j=; j<=m; j++)
{
cin>>ch;
if(ch=='H') vect_h.push_back(make_pair(i,j)),cnt++;
if(ch=='m') vect_m.push_back(make_pair(i,j));
} for(int i=; i<vect_m.size(); i++)
{
int a=vect_m[i].first, b=vect_m[i].second;
for(int j=; j<vect_h.size(); j++)
{
int c=vect_h[j].first, d=vect_h[j].second;
int dis=abs(c-a)+abs(d-b); add_node(i+,cnt+j+,dis,,);
add_node(cnt+j+,i+,-dis,,);
}
} for(int i=; i<vect_m.size(); i++) //添加源点
{
add_node(,i+,,,);
add_node(i+,,,,); }
for(int j=; j<vect_h.size(); j++) //添加汇点
{
add_node(cnt+j+,cnt*+,,,);
add_node(cnt*+,cnt+j+,,,);
}
add_node(cnt*+,cnt*+, , , ); //这是为了每次只流过1。再汇点后面再加个汇点,容量是1,但是每次spfa后都不增加flow。
add_node(cnt*+,cnt*+, , , );
cout<<cal(,cnt*+)<<endl;
}
return ;
}

AC代码

HDU 1533 Going Home (最小费用流)的更多相关文章

  1. hdu 1533 Going Home 最小费用流

    构建地图非常easy bfs预处理地图.距离的成本 来源所有m建方,流程1费0 m所有H建方,流程1距离成本 H汇点建设成为各方.流程1费0 #include<cstdio> #inclu ...

  2. 【HDU 1533】 Going Home (KM)

    Going Home Problem Description On a grid map there are n little men and n houses. In each unit time, ...

  3. POJ 2195 Going Home / HDU 1533(最小费用最大流模板)

    题目大意: 有一个最大是100 * 100 的网格图,上面有 s 个 房子和人,人每移动一个格子花费1的代价,求最小代价让所有的人都进入一个房子.每个房子只能进入一个人. 算法讨论: 注意是KM 和 ...

  4. HDU 1533 Going Home(KM完美匹配)

    HDU 1533 Going Home 题目链接 题意:就是一个H要相应一个m,使得总曼哈顿距离最小 思路:KM完美匹配,因为是要最小.所以边权建负数来处理就可以 代码: #include <c ...

  5. Going Home (hdu 1533 最小费用流)

    集训的图论都快结束了,我才看懂了最小费用流,惭愧啊. = = 但是今天机械键盘到了,有弄好了自行车,好高兴\(^o^)/~ 其实也不是看懂,就会套个模板而已.... 这题最重要的就是一个: 多组输入一 ...

  6. HDU 1533 最小费用最大流(模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=1533 这道题直接用了模板 题意:要构建一个二分图,家对应人,连线的权值就是最短距离,求最小费用 要注意void ...

  7. hdu 1533 Going Home 最小费用最大流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533 On a grid map there are n little men and n house ...

  8. Going Home HDU - 1533 费用流

    http://acm.hdu.edu.cn/showproblem.php?pid=1533 给一个网格图,每两个点之间的匹配花费为其曼哈顿距离,问给每个的"$m$"匹配到一个&q ...

  9. HDU 1533

    http://acm.hdu.edu.cn/showproblem.php?pid=1533 人和房子数量相同,每个人进房子,费用是人到房子的曼哈顿距离,求最小费用 可用最小费用最大流求解,建立虚拟的 ...

随机推荐

  1. 《WPF程序设计指南》读书笔记——第9章 路由输入事件

    1.使用路由事件 路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件.通俗地说,路由事件会在可视树(逻辑树是其子集)上,上下routed,如果哪个节点上订阅了 ...

  2. docker下PHP+Nginx+HHVM运行环境

    Dockerfile 准备开始,我们创建一个 Dockerfile —— Dockerfile 包含如何创建所需镜像的指令. FROM    centos:centos6MAINTAINER Mike ...

  3. EXPLAIN句法 优化表结构

    EXPLAIN tbl_name or EXPLAIN SELECT select_options EXPLAIN tbl_name是DESC[RIBE] tbl_name或SHOW COLUMNS ...

  4. 一个Makefile

    CC = g++ CCFLAGS = -O3 -DNDEBUG INC = -I ../../include SRC = $(wildcard *.cpp) OBJ = $(patsubst %.cp ...

  5. hibernate动态创建数据库表名几种方式

    数据库中数据量很大, 但又不可以删除时同时又要优化程序检索数据时间. 答:方式有很多比如 创建数据库表分区,创建索引, 存储过程等; 我这里采用动态创建数据库表的方式. 完全可以在不创建表分区情况下实 ...

  6. 关于mapreduce过程中出现的错误:Too many fetch-failures

    Reduce task启动后第一个阶段是shuffle,即向map端fetch数据.每次fetch都可能因为connect超时,read超时,checksum错误等原因而失败.Reduce task为 ...

  7. Python的注释

    任何时候,我们都可以给程序加上注释.注释是用来说明代码的,给自己或别人看,而程序运行的时候,Python解释器会直接忽略掉注释,所以,有没有注释不影响程序的执行结果,但是影响到别人能不能看懂你的代码. ...

  8. Telerik_2012_Q3 RadGrid 汉化

    ChineseRadGridLocalizationProvider.cs using System; using System.Collections.Generic; using System.L ...

  9. PD 脚本中列名注释用Name属性

    操作步骤:Database=>Generate Datatabase=>Format选项卡=>勾选 Generate name in empty comment项

  10. linux samba.tar.gz安装和配置

    安装步骤: 1. tar -xzvf samba-3.5.10.tar.gz2. cd samba-3.5.103. cd source34. ./autogen.sh  如果出现:./autogen ...