poj2195 bfs+最小权匹配
题意:给个矩阵,矩阵里有一些人和房子(人数和房子数相等),一个人只进一个房子(可以路过房子而不进),每走一步花费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+最小权匹配的更多相关文章
- HDU(1853),最小权匹配,KM
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 Cyclic Tour Time Limit: 1000/1000 MS (Java/Other ...
- Poj(3686),最小权匹配,多重匹配,KM
题目链接 The Windy's | Time Limit: 5000MS | Memory Limit: 65536K | | Total Submissions: 4939 | Accepted: ...
- POJ 3565 Ants (最小权匹配)
题意 给出一些蚂蚁的点,给出一些树的点,两两对应,使他们的连线不相交,输出一种方案. 思路 一开始没想到怎么用最小权匹配--后来发现是因为最小权匹配的方案一定不相交(三角形两边之和大于第三边)--还是 ...
- UVALIVE 4970 最小权匹配
首先贴一下这道题的BNU地址,UVA地址自己找吧. http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=11852 题意:这道题的意思就是,给你N个棋子的 ...
- POJ 2400 最小权匹配
吐槽:首先,这道题的输入居然是错的.要将上下两个矩阵的位置换一下才可以出样例,也就是上面那个矩阵是employee对Supervisor的打分,下面那个矩阵才是Supervisor对employee的 ...
- poj 2516(拆点+最小权匹配)
题目链接:http://poj.org/problem?id=2516 思路:考虑某种货物,由于某个订货商可能接受来自不同地区的货物,而某一地区的货物也可能送给不同的订货商,显然不能直接进行匹配,必须 ...
- poj 3686(拆点+最小权匹配)
题目链接:http://poj.org/problem?id=3686 思路:显然工件为X集,机器为Y集合.由于每个机器一次只能加工一个部件,因此我们可以将一台机器拆成N个点,至于部件与机器之间连多大 ...
- poj 2195(KM求最小权匹配)
题目链接:http://poj.org/problem?id=2195 思路:我们都知道KM使用来求最大权匹配的,但如果要求最小权匹配,只需把图中的权值改为负值,求一次KM,然后权值和取反即可. ht ...
- 【POJ 2400】 Supervisor, Supervisee(KM求最小权匹配)
[POJ 2400] Supervisor, Supervisee(KM求最小权匹配) Supervisor, Supervisee Time Limit: 1000MS Memory Limit ...
随机推荐
- java获取服务器一些信息的方法
request.getServletContext().getRealPath("/") 获取项目所在服务器的全路径,如:D:\Program Files\apache-tomca ...
- Model中的验证规则
一.能够使用Model的Attribute进行服务端数据验证 本文目录 一.概述 二.MVC提供的常用上下文 三.自定义正则表达式验证 一.概述 为了确保数据的安全性,由Client发送到服务端的每一 ...
- 一条shell统计代码行数
Xcode统计代码,用shell命令即可,非常简单.打开终端,进入你的工程目录,执行下列代码 find . -name "*.m" -or -name "*.h" ...
- layui内置loading等待加载
点击功能按钮之后 var loading = layer.load(0, { shade: false, time: 2*1000 }); 参数: icon:0,1,2 loading风格 shade ...
- <Android 应用 之路> 简易贪吃蛇
最简单的贪吃蛇 最近想着忙里偷闲写点简单的Android应用,增加一些生活乐趣,由于平时工作主要精力并不是集中在书写apk上,更多的是解决代码问题和维护模块稳定,但是写代码本身是一件比较有趣的事情,因 ...
- selenium+python之自动换测试用例执行
1.一个用例为一个完整的场景,从用户登陆系统到最终退出并关闭浏览器. 2.一个用例只验证一个功能点,不要试图在用户登陆系统后把所有的功能都验证一遍. 3.尽可能少的编写逆向逻辑用例.一方面因为逆向逻辑 ...
- Postgres 9.11 网络地址类型函数和操作符
9.11. 网络地址类型函数和操作符 Table 9-31 显示了可以用于 cidr 和 inet 的操作符. 操作符 <<,<<= >>,和 >>= ...
- HYSBZ 1010 玩具装箱toy (决策单调DP)
题意: 有n个玩具,要将它们分为若干组,玩具长度C可能不同.给出n个玩具的摆放顺序,连续的任意多个玩具都可以成为一组.区间[i,j]成为一组的费用是cost=(j-i+Sigma(Ck)-L)2且i& ...
- phar打包项目压力对比测试
工具 http_load 测试url: http://api.test.chaoma.me/agent/ad/good_goods/query http://api.test.chaoma.me/ag ...
- UVA 12325 Zombie'sTreasureChest 宝箱 (分类枚举)
看上去非常像背包的问题,但是体积太大了. 线性规划的知识,枚举附近点就行了,优先选性价比高的, 宝物有两种体积为S0,价值V0,体积S1,价值V1. 枚举分以下几种: 1:枚举拿宝物1的数量,然后尽量 ...