POJ 2195 Going Home | 带权二分图匹配
给个地图有人和房子
保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价
问让人都住在房子里最小代价
显然是个带权二分图最大匹配
转化成以一个网络,规定w是容量,c是代价
1.S向人连边,w=1,c=0
2.房子向T连边,w=1,c=0
3.人向房子连边 w=1,c=距离
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define N 10000
#define INF 1000000000
using namespace std;
deque <int> q;
int head[N],lev[N],dist[N],n,m,ecnt=1,vis[N],S,T,ans,H,M;
char mp[110][110];
struct adj
{
int nxt,v,w,c;
}e[200*200];
int Abs(int x)
{return x>0?x:-x;}
struct coor
{
int x,y;
int operator - (const coor &a)const
{return Abs(x-a.x)+Abs(y-a.y);}
};
coor make(int x,int y)
{
coor ret;
ret.x=x,ret.y=y;
return ret;
}
vector <coor> house,man;
inline void add(int u,int v,int w,int c)
{
e[++ecnt].v=v,e[ecnt].w=w,e[ecnt].c=c,e[ecnt].nxt=head[u],head[u]=ecnt;
e[++ecnt].v=u,e[ecnt].w=0,e[ecnt].c=-c,e[ecnt].nxt=head[v],head[v]=ecnt;
}
inline int spfa(int s,int t)
{
int v;
memset(vis,0,sizeof(vis));
for (int i=s;i<=t;i++) dist[i]=INF;
dist[t]=0,vis[t]=1;
q.push_back(t);
while (!q.empty())
{
int u=q.front();q.pop_front();
for (int i=head[u];i;i=e[i].nxt)
if (e[i^1].w>0 && dist[v=e[i].v]>dist[u]-e[i].c)
{
dist[v]=dist[u]-e[i].c;
if (!vis[v])
{
vis[v]=1;
if (!q.empty() && dist[v]<dist[q.front()])
q.push_front(v);
else
q.push_back(v);
}
}
vis[u]=0;
}
return dist[s]<INF;
}
inline int dfs(int x,int flow)
{
if (x==T)
return vis[T]=1,flow;
int used=0,tmp,v;
vis[x]=1;
for (int i=head[x];i;i=e[i].nxt)
if (!vis[v=e[i].v] && e[i].w>0 && dist[x]-e[i].c==dist[v])
{
tmp=dfs(v,min(e[i].w,flow-used));
if (tmp>0)
ans+=tmp*e[i].c,e[i].w-=tmp,e[i^1].w+=tmp,used+=tmp;
if (used==flow) break;
}
return used;
}
inline int CostFlow()
{
int Flow=0;
while (spfa(S,T))
{
vis[T]=1;
while (vis[T])
{
memset(vis,0,sizeof(vis));
Flow+=dfs(S,INF);
}
}
return Flow;
}
void init()
{
memset(head,0,sizeof(head));
man.clear();
house.clear();
ans=M=H=0;
ecnt=1;
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
if (n==0 && m==0) break;
init();
for (int i=1;i<=n;i++)
scanf("%s",mp[i]+1);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (mp[i][j]=='m')
man.push_back(make(i,j)),M++;
else if (mp[i][j]=='H')
house.push_back(make(i,j)),H++;
T=H+M+1;
for (int i=0;i<M;i++)
for (int j=0;j<H;j++)
add(i+1,M+j+1,1,man[i]-house[j]);
for (int i=1;i<=M;i++)
add(S,i,1,0);
for (int i=1;i<=H;i++)
add(M+i,T,1,0);
CostFlow();
printf("%d\n",ans);
} return 0;
}
POJ 2195 Going Home | 带权二分图匹配的更多相关文章
- POJ 2195 Going Home (带权二分图匹配)
POJ 2195 Going Home (带权二分图匹配) Description On a grid map there are n little men and n houses. In each ...
- 运动员最佳匹配问题 KM算法:带权二分图匹配
题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...
- 费用流模板(带权二分图匹配)——hdu1533
/* 带权二分图匹配 用费用流求,增加源点s 和 汇点t */ #include<bits/stdc++.h> using namespace std; #define maxn 1000 ...
- hdu5045:带权二分图匹配
题目大意 : n个人 做m道题,其中 每连续的n道必须由不同的人做 已知第i人做出第j题的概率为pij,求最大期望 思路:考虑每连续的n道题 都要n个人来做,显然想到了带权的二分图匹配 然后就是套模板 ...
- Glorious Brilliance (最短路 + 带权二分图匹配)
这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建 ...
- [NOI2012]美食节——费用流(带权二分图匹配)+动态加边
题目描述 小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜品.当所有的同学点餐结束后,菜品的制作任务就会分配给每个厨师.然后每个厨师就会同时开始 ...
- [HAOI2008]移动玩具(状压&带权二分图)
题目描述 • 一个 4 × 4 的 0/1 矩阵 • 每次可以交换相邻两个元素 • 求从初始状态到目标状态的最小交换次数 输入格式 前四行,每行一个长为 4 的 0/1 字符串,描述初始状态. 后四行 ...
- Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)
Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配) Description 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的 ...
- KM(Kuhn-Munkres)算法求带权二分图的最佳匹配
KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后, ...
随机推荐
- HJ浇花
题目描述 HJ养了很多花(99999999999999999999999999999999999盆),并且喜欢把它们排成一排,编号0~999999999999999999999999999999999 ...
- Windows API窗口绘图程序设计
任务目标 设计一个简单的Windows 窗口程序,在程序窗口内任意位置按下鼠标左键,可绘制范围在10-100之间随机大小的正方形.并且显示的正方形用红色填充. 效果图 小结 程序先是触发鼠标左键点击事 ...
- JavaScript---ECMA对象
1.对象的概念及分类 1.1 ECMAScript中没有类,但定义了“对象”,逻辑上等价于其他程序设计语言中的类. var o = new Object(); 1.2 本地对象(native obje ...
- 有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果
问题:有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果 解决: 页面代码是至上而下执行的,如果你的这个标签在< ...
- Linux段式管理与页式管理
内存管理有2种机制:1.段式管理:2.页式管理 在80386CPU中增加了2个寄存器:1.全局性的段描述表寄存器GDTR 2.局部性的段描述表寄存器LDTR 段寄存器的高13位用于在全局或局部描述表项 ...
- 裸机——iNand
1.先晓得iNand的基础知识 iNand是在SD卡基础上发展来的,而SD卡是在MMC的基础上发展来的,MMC是在Nand的基础上发展来的 我们晓得Nand的基础知识,而MMC对Nand大致做了两个改 ...
- Linux YUM (Yellowdog Updater, Modified) Commands for Package Management
Linux YUM (Yellowdog Updater, Modified) Commands for Package Management In this article, we will lea ...
- 牛客暑假多校第二场J-farm
一.题意 White Rabbit has a rectangular farmland of n*m. In each of the grid there is a kind of plant. T ...
- python-4函数式编程
1-高阶函数 变量可以指向函数. def add(x, y, f): 例如f参数为函数 编写高阶函数,就是让函数的参数能够接收别的函数. Python内建了map()和reduce()高阶函数. ...
- python-2函数
http://docs.python.org/3/library/functions.html 或者菜鸟中文资料 1-使用函数 abs(-20)#求绝对值 max(1,4,200,3,2) #求最大的 ...