目录
完成情况 | 题目 | 出处 |
---|---|---|
Kejin Game | UVALive 7264 | |
Teamwork | HDU 4494 | |
Less Time, More profit | HDU 5855 | |
网络流五 | Hihocoder 1398 | |
AC | Going Home | POJ 2195 |
Sofa, So Good | Codeforces Gym 100642H | |
AC | zsy与wj的连边之战 | FLOJ 906 |
二分图
首先先有几个概念:
匹配:就是用一条边连接两个未被匹配的点,叫做一个匹配。匹配可以做动词,也可以作名词。
边覆盖:顾名思义,就是一个图中选一些边,使得这些边的端点包含所有的点。
点覆盖:类似边覆盖,就是选一些点,使得图的所有边的端点至少有一个在选的点中。
独立集:就是每个点都相互没有连边的点集。
团:就是每个点都直接连边的点集。
那么由定义得,一个独立集对应反图的一个团。
那么我们还有如下定理:
(1)
对于没有孤点的图,最大匹配+最小边覆盖==边数。
(或者说每个点拆成两个点,
a1,a2
,如果有一条
a−b
的有向边,在新图中连一条
a1−b2
的边。新图的最大匹配数+最小边覆盖=点数,这样再算的时候就不用算独立点了。)
(2)
最大独立集+最小点覆盖==边数
那么对于二分图,我们还有一个定理:
(3)
最小点覆盖=最大匹配数。
证明这些定理的话,别问我。
那么还是从基础开始:
匈牙利算法
这个算法是计算二分图的最大匹配的,通过不停的暴力找点来强行加边来得到答案,代码也很简单:
#include<cstdio>
#include<cstring>
using namespace std;
const int N =1002;
bool line[N][N];
bool used[N];
int to[N];
int n,m,e;
bool find(int x)
{
for (int j=1;j<=m;j++)
{
if (line[x][j]==true && !used[j])
{
used[j] = true;//强行找
if (to[j]==0 || find(to[j]) )
{
to[j] = x;
return true;
}
}
}
return false;
}
int hungarian()
{
int ans =0;
for (int i=1;i<=n;i++)
{
memset(used,0,sizeof used);
if (find(i)) ans++;
}
return ans;
}
当然找二分图的匹配也可以通过网络流来乱搞。
例题:
- 春天来了
题面:
春天来了!又到了交配的季节。
这里有n个男孩纸和n个女孩纸要组成n对好朋友。
每个人都有一个腼腆值,每当一个男孩纸和一个女孩纸成为好朋友,他们总是会有那么一点点尴尬,那么他们产生的尴尬值就是他们腼腆值的乘积。
为了让孩纸们都能找到好朋友,我们现在要帮助他们进行男女配对,目标是让他们所产生的尴尬值总和最小。
N<=1e5。
题解
放在这里是来搞笑的,因为根本不是一个二分图的题,由切比雪夫不等式可得 顺序和≥乱序和≥反序和 ,所以直接反序就可以了。 - Heoi 2012 朋友圈(bzoj2744)
明显 A 国只能选一奇一偶,而B 国的话,将不能做朋友的连一条边,就变成了一个二分图,然后跑一下最小点覆盖就可以了,所以我们只用枚举一下 A 国选哪些人。 - Cdoj 1432
因为放的格子只有1×2 的大小,所以一个点被放的话会影响其周围的点,但是周围的点又不会互相影响,所以是一个二分图,直接跑一下就可以了。
网络流
基础在另一篇博客:传送门
例题
-
- Poj 1273
模板题,而且好像错的程序都可以A掉。
UVALive 7264
我们明白这个是一个最小割。这个其实就是用最小割完成边的选择和合并的问题。每个点拆成两个点,之间连一条 ci 表示直接氪掉这个技能。父节点向它连一条流量为 bi 的边,表示断掉这条边的代价。源点向它连一条 ai 的边,就是你要正常学习这个技能要花费的代价。HDU 3987
这种相当于是双关键字排序,有一种常见套路。我们可以给权值乘一个值,来让他远远大于我们选择的边数,然后每条边加上 1 ,就代表我们额外选择了一条边。就是说让第一关键字的值带来的影响远大于第二关键字,这样子排出来的就是最优解。
费用流
基础在另一篇博客:传送门
例题
Hdu 6118
这个明显是费用流,但是好像不是我们熟知的最大流最小费用流,怎么办呢,每个点源点向它连一条能生产数量和生产价值的边,向汇点连一条能出售数量和出售价格的边。然后每个点向其他能到达的点连一(inf,运输价格) 的边。但是我们不一定跑满流,怎么办呢?每一个点再向汇点连一条 (生产数量,生产价格) 的边,这样子可以直接跑费用流,相当于多连的边等于把多卖的反悔。hdu4494
注意到每种工人是独立的,所以我们独立来建图。我们把一个工作拆成两个点,一个点用来接收,一个点用来送人,那么源点向受点连一条 (工人数,1) 的边。互相向提供点连 (工人数,0) 的边。收点向汇点连 (工人数,0) 的边。然后每个人往其他地方连 (inf,0) 的边。
最大权闭合图
在一个图中,我们选取一些点构成集合,记为
V
,且集合中的出边(即集合中的点的向外连出的弧),所指向的终点(弧头)也在
大多数时候就是你看到一个问题,它有正点有负点,然后你需要找最大值,八成就是类似问题。
解法
源点向正权点连一条边,汇点向负权点连一条边,容量都是权值的绝对值。原有的图上的边的容量变成
例题
- Hdu 5855
二分一下时间。然后我们建图的时候向工厂建负边,商店建正边,因为要建工厂才能建商店,所以有先后关系,就是裸的了。
- [hihocoder]网络流五
与上图一样,请人是负,玩是正。
zsy与wj的连边之战
这道题,我们先把有保护关系的植物连边(被保护的向保护的连边,特别的,同一行相临的也要连边,因为这个也有先后。)(或者说是打植物的先后关系),这样子,我们不难发现,这个就是一个最大权闭合图。因为一个点的出度一定要在这个图中,要不然就不能打掉。但是还没完,有些点会形成环,这些肯定打不掉,要先用 tarjan 缩环或者用 top 排序打标记。
二分图带权匹配
写不来 KM ,就直接写费用流。
例题
- Poj 2195
简直就是版题,一个人与宾馆连边,然后代价是曼哈顿距离,然后跑就好了。
- UVA Live 6129 (Codeforces Gym 100642H)
因为有关键字,所以要先满足第一关键字,将结果跑出来之后再满足第二关键字。具体的做法是将第一关键字的结果带入到第二关键字中再跑。