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写法的更多相关文章

  1. POJ1915Knight Moves(单向BFS + 双向BFS)

    题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...

  2. Addition Chains POJ - 2248 (bfs / dfs / 迭代加深)

    An addition chain for n is an integer sequence <a0, a1,a2,...,am=""> with the follow ...

  3. uoj#80 二分图最大权匹配

    题意:给定二分图,有边权,求最大边权匹配.边权非负. 解:KM算法求解最大权完备匹配. 完备匹配就是点数少的那一边每个点都有匹配. 为了让完备匹配与最大权匹配等价,我们添加若干条0边使之成为完全二分图 ...

  4. 【bzoj1060】[ZJOI2007]时态同步

    题目描述 小Q在电子工艺实习课上学习焊接电路板.一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字1,2,3-.进行标号.电路板的各个节点由若干不相交的导线相连接,且对于电路板的任何两个节点 ...

  5. APIO2017商旅

    传送门(PDF) 题目大意:有$N$个点,$M$条有向边,$K$种物品,在不同的点可以用不同的价格买入或卖出某一种商品. 任意时刻至多持有一种物品,不能在同一个点先买再卖,求收益与长度之比最大的点数$ ...

  6. [LeetCode] 864. Shortest Path to Get All Keys 获得所有钥匙的最短路径

    We are given a 2-dimensional grid. "." is an empty cell, "#" is a wall, "@& ...

  7. 【剑指Offer】60、按之字形顺序打印二叉树

    题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 题解:BFS 主要的方法与BFS写法没什么区 ...

  8. bzoj3436小K的农场

    bzoj3436小K的农场 题意: n个数,知道m条关系:a-b≥c.a-b≤c或a==b.问是否存在满足所有关系的情况.n≤10000,m≤10000. 题解: 差分约束.因为只要求是否满足,因此最 ...

  9. 【LeetCode】代码模板,刷题必会

    目录 二分查找 排序的写法 BFS的写法 DFS的写法 回溯法 树 递归 迭代 前序遍历 中序遍历 后序遍历 构建完全二叉树 并查集 前缀树 图遍历 Dijkstra算法 Floyd-Warshall ...

随机推荐

  1. BZOJ 1444 有趣的游戏(AC自动机+矩阵快速幂)

    真的是很有趣的游戏... 对每个单词构建好AC自动机后,由于单词都是相同长度的且不同,所以不会出现互相为子串的形式. 那么我们对AC自动机上的节点构建转移矩阵.对于每个单词末尾的节点.该节点的出边仅仅 ...

  2. CIR,CBS,EBS,PIR,PBS 名词解释 令牌桶应用

    为了达到上述目的,我们需要对进入网络的流量进行监督,实现CAR(Committed Access Rate). CAR:将进入网络的用户流量的速率限制在约定的范围之内,从而避免引起网络拥塞. CIR( ...

  3. Best Reward HDU - 3613(马拉车+枚举+前缀和)

    题意: 给你一串字符串,每个字符都有一个权值,要求把这个字符串在某点分开,使之成为两个单独的字符串 如果这两个子串某一个是回文串,则权值为那一个串所有的字符权值和 若不是回文串,则权值为0 解析: 先 ...

  4. [BZOJ3172]单词

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会 ...

  5. 【刷题】洛谷 P3808 【模板】AC自动机(简单版)

    题目背景 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次, ...

  6. C内存对齐问题-bus error!总线错误!其实是 字符串字面量修改问题!

    最近写个小程序,出现bus error! int main(void) { /** * char :1个字节 * char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也 ...

  7. miya--图片上传--搭建分布式文件服务器(FastDFS+Nginx)

    资料获取(FastDFS+Nginx): 链接:https://pan.baidu.com/s/1kUI5WH5 密码:kzfd 安装rz,sz功能: yum install lrzsz 主攻: 利用 ...

  8. C++中添加配置文件读写方法

    比如有一个工程,一些变量有可能需要不时的修改,这时候可以通过从配置文件中读取该数值,需要修改时只需要修改配位文件即可. 比如有一个这样的变量m_nTest; 我么可以写两个函数ReadConfig() ...

  9. POJ2234:Matches Game(Nim博弈)

    Matches Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12325   Accepted: 7184 题目链 ...

  10. mybatis基础犯错总结

    1.关于mybatis的文件一般都是其mapper文件出错: 首先关于输入参数parameterType出错: (1)基本数据类型:如果输入参数只有一个,其数据类型可以是基本数据类型,也可以是自己定的 ...