KM bfs写法
KM bfs写法
2018astar资格赛的第三题整数规划。
把\(x, y\)看成二分图两边的顶标,\(a_{ij}\)就是二分图的边权,整道题其实就是求二分图的最大权匹配。
然后打了个\(dfs\)的\(KM\),\(TLE\)了,后来听别人说要用\(bfs\)的写法,因为那个才是真正的\(O(n^3)\),\(dfs\)的写法最坏情况还是\(O(n^4)\)。
原理是一样的,只不过\(bfs\)有一点点像迭代,每一次也只是搜\(diff=0\)的情况,而且右边的点只会搜索一次(或者说是左边的点只会搜索一次,即左边的每个点只会进队一次),用\(pre\)记住当前的交错路径,找到未匹配的就可以沿交错路径进行修改。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=210;
const LL inf=1LL<<60;
int n;
namespace KM
{
int n;
LL mat[maxn][maxn]; //边权
int matcha[maxn], matchb[maxn]; //左边的点匹配的右边点;右边的点匹配的左边点
LL marka[maxn], markb[maxn]; //左顶标;右顶标
LL slack[maxn]; //松弛数组
bool visa[maxn], visb[maxn]; //访问标记
int head, tail;
int q[maxn], pre[maxn]; //队列;交错路径
bool check(int cur)
{
visb[cur]=true; //标记cur已搜索
if (matchb[cur]) //已匹配,即当前匹配失败
{
if (!visa[matchb[cur]]) //匹配的点是否已进队
{
q[++tail]=matchb[cur];
visa[matchb[cur]]=true;
}
return false;
}
//未匹配,即当前匹配成功,沿交错路径进行匹配
while (cur)
swap(cur, matcha[matchb[cur]=pre[cur]]);
return true;
}
void bfs(int start)
{
fill(visa, visa+1+n, false);
fill(visb, visb+1+n, false);
fill(slack, slack+1+n, inf);
head=tail=1;
q[1]=start;
visa[start]=true;
while (1)
{
while (head<=tail)
{
int cur=q[head++];
for (int i=1; i<=n; ++i)
{
LL diff=marka[cur]+markb[i]-mat[cur][i];
if (!visb[i] && diff<=slack[i]) //visb=true说明已搜索,无需更新slack和pre,也是保证pre的正确性
{
slack[i]=diff;
pre[i]=cur;
if (diff==0) //diff=0,可以尝试匹配
if (check(i)) return; //匹配成功可直接返回
}
}
}
LL delta=inf;
for (int i=1; i<=n; ++i)
if (!visb[i] && slack[i]) delta=min(slack[i], delta);
for (int i=1; i<=n; ++i) //松弛
{
if (visa[i]) marka[i]-=delta;
if (visb[i]) markb[i]+=delta;
else slack[i]-=delta; //维护slack的正确性(参考diff的计算及marka,markb的变化)
}
head=1, tail=0;
for (int i=1; i<=n; ++i)
if (!visb[i] && !slack[i] && check(i)) return;
//松弛后尝试匹配diff=0的点。
}
}
void solve()
{
fill(matcha, matcha+1+n, 0);
fill(matchb, matchb+1+n, 0);
fill(markb, markb+1+n, 0);
for (int i=1; i<=n; ++i)
{
marka[i]=0;
for (int j=1; j<=n; ++j)
marka[i]=max(marka[i], mat[i][j]);
}
for (int i=1; i<=n; ++i) bfs(i);
}
}
void read()
{
scanf("%d", &n);
KM::n=n;
for (int i=1; i<=n; ++i)
for (int j=1; j<=n; ++j)
{
int x;
scanf("%d", &x);
KM::mat[i][j]=-x;
}
}
void solve()
{
KM::solve();
LL ans=0;
for (int i=1; i<=n; ++i)
ans+=KM::marka[i]+KM::markb[i];
printf("%lld\n", -ans);
}
int main()
{
int casesum;
scanf("%d", &casesum);
for (int i=1; i<=casesum; ++i)
{
printf("Case #%d: ", i);
read();
solve();
}
return 0;
}
KM bfs写法的更多相关文章
- POJ1915Knight Moves(单向BFS + 双向BFS)
题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...
- Addition Chains POJ - 2248 (bfs / dfs / 迭代加深)
An addition chain for n is an integer sequence <a0, a1,a2,...,am=""> with the follow ...
- uoj#80 二分图最大权匹配
题意:给定二分图,有边权,求最大边权匹配.边权非负. 解:KM算法求解最大权完备匹配. 完备匹配就是点数少的那一边每个点都有匹配. 为了让完备匹配与最大权匹配等价,我们添加若干条0边使之成为完全二分图 ...
- 【bzoj1060】[ZJOI2007]时态同步
题目描述 小Q在电子工艺实习课上学习焊接电路板.一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字1,2,3-.进行标号.电路板的各个节点由若干不相交的导线相连接,且对于电路板的任何两个节点 ...
- APIO2017商旅
传送门(PDF) 题目大意:有$N$个点,$M$条有向边,$K$种物品,在不同的点可以用不同的价格买入或卖出某一种商品. 任意时刻至多持有一种物品,不能在同一个点先买再卖,求收益与长度之比最大的点数$ ...
- [LeetCode] 864. Shortest Path to Get All Keys 获得所有钥匙的最短路径
We are given a 2-dimensional grid. "." is an empty cell, "#" is a wall, "@& ...
- 【剑指Offer】60、按之字形顺序打印二叉树
题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 题解:BFS 主要的方法与BFS写法没什么区 ...
- bzoj3436小K的农场
bzoj3436小K的农场 题意: n个数,知道m条关系:a-b≥c.a-b≤c或a==b.问是否存在满足所有关系的情况.n≤10000,m≤10000. 题解: 差分约束.因为只要求是否满足,因此最 ...
- 【LeetCode】代码模板,刷题必会
目录 二分查找 排序的写法 BFS的写法 DFS的写法 回溯法 树 递归 迭代 前序遍历 中序遍历 后序遍历 构建完全二叉树 并查集 前缀树 图遍历 Dijkstra算法 Floyd-Warshall ...
随机推荐
- BZOJ 2186 沙拉公主的困惑(预处理逆元+欧拉函数)
题意:求1-n!里与m!互质的数有多少?(m<=n<=1e6). 因为n!%m!=0,所以题目实际上求的是phi(m!)*n!/m!. 预处理出这些素数的逆元和阶乘的模即可. # incl ...
- BZOJ 1237 配对(DP)
给出两个长度为n的序列.这两个序列的数字可以连边当且仅当它们不同,权值为它们的绝对值,求出这个二分图的最小权值完全匹配.没有输出-1. n<=1e5.用KM会TLE+MLE. 如果连边没有限制的 ...
- 插件-监控页面加载之loading
查看效果点https://icedjuice.github.io/plug-in/loading/loading.html 简单易用的loading插件,该插件并不是真正的监控页面的资源加载过程,而是 ...
- DjangoORM外键操作
Django ORM 外键操作 经常修改的东西一般不放到内存里面,而是放到一张表里.表跟表之间是可以存在关系的,最基本的就是一对多的关系. models.ForeignKey(ColorDic) 1. ...
- Android NDK 编译选项设置[zhuan]
http://crash.163.com/#news/!newsId=24 在Android NDK开发中,有两个重要的文件:Android.mk和Application.mk,各尽其责,指导编译器如 ...
- 没有为扩展名“.cshtml”注册的生成提供程序。
新建的mvc4 空项目,然后从其他项目里拷贝shared文件夹和_ViewStart.cshtml文件过去,然后在@符号上出现 没有为扩展名“.cshtml”注册的生成提供程序.错误 解决方法: 需要 ...
- struts2 文件下载的处理
- 题解【bzoj2038 [2009国家集训队]小Z的袜子(hose)】
Description \(m\) 个询问,每次给出一个区间,求从这个区间中取出两个数使得它们同色的概率. \(n,m,a_i \leq 50000\) Solution 莫队模板题 最后的概率是 选 ...
- 题解【bzoj3240 [NOI2013]矩阵游戏】
挖坑2333 等我把代码写完了再写
- Leetcode 492. 构造矩形
1.题目描述 作为一位web开发者, 懂得怎样去规划一个页面的尺寸是很重要的. 现给定一个具体的矩形页面面积,你的任务是设计一个长度为 L 和宽度为 W 且满足以下要求的矩形的页面.要求: 1. 你设 ...