题意:

  一个矩阵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. css3 旋转效果加上双面显示效果

    在学习Css3的过程中,我想做一个类似金字塔,菱形翻页效果,如图这种效果 如是,我自己设计了一个,不带js的旋转效果: 1>第一步我先设计了一个方块,内含一个旋转了45deg的小方块,代码如下: ...

  2. web sevice 生成代理类及使用

    一.生成代理类: VS2008下这样写 wsdl.exe /l:cs /out:D:/ProxyServices.cs http://localhost/WebService.asmx VS2010下 ...

  3. python学习笔记10(函数一): 函数使用、调用、返回值

    一.函数的定义 在某些编程语言当中,函数声明和函数定义是区分开的(在这些编程语言当中函数声明和函数定义可以出现在不同的文件中,比如C语言),但是在Python中,函数声明和函数定义是视为一体的.在Py ...

  4. poj 2777 Count Color(线段树)

    题目地址:http://poj.org/problem?id=2777 Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Subm ...

  5. C# SqlConnection

    public static ArrayList Connect(string connectionString, string commandText) { ArrayList retValList ...

  6. java、js的编码、解码

    如果在地址栏挂载参数,特别是包含中文,往往要进行编码,取值时再解码,以下是java和js中编码.解码的各自方法. java: @Test public void test3() throws Unsu ...

  7. [转载]ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL

    引言-- 在初级篇中,我们介绍了如何利用基于ASP.NET MVC的Web程序中的Global文件来简单的重写路由.也介绍了它本身的局限性-依赖于路由信息中的键值对: 如果键值对中没有的值,我们无法将 ...

  8. uva 10369

    数组开小了  还RE了一遍.......  最小生成树    按费用从小到大排... #include <iostream> #include <algorithm> #inc ...

  9. hdu 2897 邂逅明下 博弈论

    这个分区间: 1<=n%(p+q)<=p 必败 其他必胜! 代码如下: #include<iostream> #include<stdio.h> #include& ...

  10. codeforces #313 div1 C

    同BZOJ 3782 上学路线 QAQ 还比那个简单一点 把坐标(1,1)-(n,m)平移成(0,0)-(n-1,m-1) 设dp[i]表示从(1,1)出发第一次经过障碍且到达第i个障碍的方案数 首先 ...