题意:给个矩阵,矩阵里有一些人和房子(人数和房子数相等),一个人只进一个房子(可以路过房子而不进),每走一步花费1美金,求所有人都进入房子的最小花费,这是典型的二分图带权匹配问题。

这题就是建图有点麻烦,但绝不抽象,直接用BFS遍历每个人到所有房子的距离,遍历出一个就拉一条人到房子有向边,建完图就是套模板了。

注意:KM算法是求最大权匹配的,要求最小权就要把所有边取相反数,最后结果再取相反数,但这只能是完美匹配,不完美匹配还要变一些。

 #include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
#define maxn 500 using namespace std; char group[][];
int index[][];
struct pos
{
int x,y;
}people[maxn],house[maxn];
struct edge
{
int to,cap;
};
vector<edge> g[maxn];
int a,b,sum_m,sum_h; const int mir[][]={{,},{,-},{,},{-,}};
int vis[][];
struct step
{
int x,y,s;
};
void init()
{
sum_m=sum_h=;
memset(people,,sizeof(people));
memset(house,,sizeof(house));
memset(index,,sizeof(index));
for(int i=;i<maxn;i++)
g[i].clear();
}
void add_edge(int from,int to,int cap)
{
g[from].push_back((edge){to,cap});
}
void bfs(int sx,int sy,int ex,int ey)
{
memset(vis,,sizeof(vis));
step now,next;
queue<step> q;
now.x=sx,now.y=sy,now.s=;
vis[sx][sy]=;
q.push(now);
while(!q.empty())
{
now=q.front();
q.pop();
if(now.x==ex&&now.y==ey)
{
add_edge(index[sx][sy],index[now.x][now.y],~now.s+);
return;
}
for(int i=;i<;i++)
{
int x=now.x+mir[i][];
int y=now.y+mir[i][];
if(x>=&&y>=&&x<a&&y<b)
{
if(!vis[x][y])
{
vis[x][y]=;
next.x=x,next.y=y,next.s=now.s+;
q.push(next);
}
}
}
}
}
int x[maxn], y[maxn], link[maxn],sx[maxn], sy[maxn];
int slack;
int DFS(int t)
{
int i, tmp;
sx[t] = ;
for (i = ; i < g[t].size(); i++)
{
edge e=g[t][i];
if (!sy[e.to])
{
tmp = x[t] + y[e.to] - e.cap;
if (tmp == )
{
sy[e.to] = ;
if (link[e.to] == - || DFS(link[e.to]))
{
link[e.to] = t;
return ;
}
}
else if (tmp < slack)
slack = tmp;
}
}
return ;
}
void KM()
{
int i, j;
for(int w=;w<sum_m;w++)
{
x[w]=;
for(int v=;v<g[w].size();v++)
{
if(g[w][v].cap>x[w])
x[w]=g[w][v].cap;
}
}
for (j = ; j < sum_h; j++)
{
y[j] = ;
}
memset(link, -, sizeof(link));
for (i = ; i < sum_m; i++)
{
while ()
{
memset(sx, , sizeof(sx));
memset(sy, , sizeof(sy));
slack = 0xfffffff;
if (DFS(i)) break;
for (j = ; j < sum_m; j++)
{
if (sx[j])
x[j] -= slack;
}
for (j = ; j < sum_h; j++)
{
if (sy[j])
y[j] += slack;
}
}
}
} int main()
{
while(scanf("%d%d",&a,&b)!=EOF,a&&b)
{
getchar();
init();
for(int i=;i<a;i++)
{
gets(group[i]);
for(int j=;j<b;j++)
{
if(group[i][j]=='m')
{
people[sum_m].x=i;
people[sum_m].y=j;
index[i][j]=sum_m;
sum_m++;
}
else if(group[i][j]=='H')
{
house[sum_h].x=i;
house[sum_h].y=j;
index[i][j]=sum_h;
sum_h++;
}
}
}
for(int n=;n<sum_m;n++)
{
for(int m=;m<sum_h;m++)
{
bfs(people[n].x,people[n].y,house[m].x,house[m].y);
}
}
/* for(int i=0;i<sum_m;i++)
{
cout<<i<<" ";
for(int j=0;j<g[i].size();j++)
cout<<g[i][j].to<<" "<<g[i][j].cap<<endl;
}*/
KM();
int ans=;
int coun = ,t=;
for (int i = ; i < sum_h; i++)
{
t = link[i];
if (t >= )
{
coun ++;
ans += g[t][i].cap;
}
}
printf("%d\n",~ans+);
}
return ;
}

poj2195 bfs+最小权匹配的更多相关文章

  1. HDU(1853),最小权匹配,KM

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 Cyclic Tour Time Limit: 1000/1000 MS (Java/Other ...

  2. Poj(3686),最小权匹配,多重匹配,KM

    题目链接 The Windy's | Time Limit: 5000MS | Memory Limit: 65536K | | Total Submissions: 4939 | Accepted: ...

  3. POJ 3565 Ants (最小权匹配)

    题意 给出一些蚂蚁的点,给出一些树的点,两两对应,使他们的连线不相交,输出一种方案. 思路 一开始没想到怎么用最小权匹配--后来发现是因为最小权匹配的方案一定不相交(三角形两边之和大于第三边)--还是 ...

  4. UVALIVE 4970 最小权匹配

    首先贴一下这道题的BNU地址,UVA地址自己找吧. http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=11852 题意:这道题的意思就是,给你N个棋子的 ...

  5. POJ 2400 最小权匹配

    吐槽:首先,这道题的输入居然是错的.要将上下两个矩阵的位置换一下才可以出样例,也就是上面那个矩阵是employee对Supervisor的打分,下面那个矩阵才是Supervisor对employee的 ...

  6. poj 2516(拆点+最小权匹配)

    题目链接:http://poj.org/problem?id=2516 思路:考虑某种货物,由于某个订货商可能接受来自不同地区的货物,而某一地区的货物也可能送给不同的订货商,显然不能直接进行匹配,必须 ...

  7. poj 3686(拆点+最小权匹配)

    题目链接:http://poj.org/problem?id=3686 思路:显然工件为X集,机器为Y集合.由于每个机器一次只能加工一个部件,因此我们可以将一台机器拆成N个点,至于部件与机器之间连多大 ...

  8. poj 2195(KM求最小权匹配)

    题目链接:http://poj.org/problem?id=2195 思路:我们都知道KM使用来求最大权匹配的,但如果要求最小权匹配,只需把图中的权值改为负值,求一次KM,然后权值和取反即可. ht ...

  9. 【POJ 2400】 Supervisor, Supervisee(KM求最小权匹配)

    [POJ 2400] Supervisor, Supervisee(KM求最小权匹配) Supervisor, Supervisee Time Limit: 1000MS   Memory Limit ...

随机推荐

  1. 把本地项目上传到github 不使用eclipse

    https://blog.csdn.net/m0_37725003/article/details/80904824

  2. VS2012快捷键消失

    我也是网上搜的不过我认为挺有效就自己摘录下来了,具体原作者也找不到,所以就下手了,望原谅. 开始菜单 -->所有程序-->Visual Studio 2012文件夹 --> Visu ...

  3. JAVA基础之Map接口

    个人理解: 个人感觉Map接口以后会经常用到,可以很清晰地查找某个对象,要熟悉其四种遍历方法.特别注意其键值对的键不能是重复的,有想定义有序存取的话,可以使用LinkedHashMap集合.不过定义自 ...

  4. Android给图片加文字和图片水印

    我们在做项目的时候有时候需要给图片添加水印,水寒今天就遇到了这样的问题,所以搞了一个工具类,贴出来大家直接调用就行. /** * 图片工具类 * @author 水寒 * 欢迎访问水寒的个人博客:ht ...

  5. js进阶之闭包

    1.首先说下什么是闭包,闭:封闭,包:就像我们的包包~:虽然我在扯淡但是也有其道理咯,闭包就有点像java里面的封装一样,包属性和方法都封装到对象内部,在外部通过共有的get.set方法获取或者设置其 ...

  6. ansys-表格

    转自http://blog.sina.com.cn/s/blog_833dee820102xwb3.html ANSYS中表格数组的定义及使用举例 ANSYS中会有许多的参数数据,这些参数的形成后要放 ...

  7. UVA 690 PipelineScheduling 位运算+dfs+剪枝

    一开始最容易想到间隔最多为n,但是结点还是太多了,需要优化. 预处理:预判一下并保存下一个可以放的位置距离之前的距离.这样可以减少很多判断. 最优化剪枝:如果当前长度+剩下没放的程序*最短间隔如果大于 ...

  8. event loop、进程和线程、任务队列

    本文原链接:https://cloud.tencent.com/developer/article/1106531 https://cloud.tencent.com/developer/articl ...

  9. openstack nova fail to create vm

    2019-05-13 14:43:27.017 47547 ERROR nova.compute.manager [req-3f1af0ed-c342-4cf3-8e76-6963053a5227 8 ...

  10. ps基础入门快捷方法总结

    1. 快速打开文件 双击Photoshop的背景空白处(默认为灰色显示区域)即可打开选择文件的浏览窗口. 2. 随意更换画布颜色 选择油漆桶工具并按住Shift点击画布边缘,即可设置画布底色为当前选择 ...