随笔分类 -  图论相关

摘要://*******************************以下是转载的*******************************************二分图匹配算法总结二分图最大匹配的匈牙利算法二分图是这样一个图,它的顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y。最大匹配:图中包含边数最多的匹配称为图的最大匹配。完美匹配:如果所有点都在匹配边上,称这个最大匹配是完美匹配。最小覆盖:最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数最小路径覆盖:用尽量少的不相交简单路 阅读全文
posted @ 2013-04-09 18:07 沐阳 阅读(1411) 评论(3) 推荐(0)
摘要:题意:给定一群人的姓名和昵称,给定了一些关系,现在要求判定姓名和昵称能够一一对应的有哪些?解法:一开始直接使用藏匿点的所有人和邮件进行构边,再用删除来判定,结果出错,为什么呢?因为我们将藏匿点的所有人和邮件连边确定的就是一种可能关系,然而题目中还隐藏了许多的可能关系,比如某人在藏匿点但是没有发邮件,那么其和其他未出现的昵称之间存在可能关系。正确的解法是确定不可能关系,因为这样更加简单,在藏匿点外的人不可能与邮件有关系。初始化所有人和所有昵称都有关系,通过排除不可能的关系即确定了可能的关系。之后再枚举每一条边,将其删除看通过最大匹配是否减小来断定这条边是不是被唯一对应。注意:如果某一组名字-昵称 阅读全文
posted @ 2013-04-08 21:09 沐阳 阅读(527) 评论(0) 推荐(0)
摘要:题意:给定一个网格,现在某些格子坐标中有一个小行星,现有一种武器能够击穿一行或者是一列的小行星,问最少使用多少次这种武器能够销毁所有的小行星。解法:由于每一个点只要被行或者列覆盖到就可以,因此可以将某一点所在的行和列进行匹配,问题就转化为求一个最小顶点覆盖就可以了,因为这样能够保证每一条边都有一个顶点在点集内。也即每个小行星都能够被所在的行或者是所在的列覆盖到。代码如下:#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <algo 阅读全文
posted @ 2013-04-08 18:28 沐阳 阅读(267) 评论(0) 推荐(0)
摘要:题意:有N个十字路口,这些十字路口通过M条路连接,边是单向的,现在要派一些伞兵去空袭这些十字路口,每个伞兵可以沿着一条路空袭沿路的十字路口,问最少要派出多少伞兵。解法:对于有向无环图求最小的路径覆盖数相当于将原图中的点拆开后,求一个最大匹配数,然后用顶点数减去最大匹配数就是最小路径覆盖了。代码如下:#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int N, M 阅读全文
posted @ 2013-04-08 13:46 沐阳 阅读(211) 评论(0) 推荐(0)
摘要:题意:有许多男女同学,他们之间互相喜欢,现要求出一个最大的独立子集出来。解法:由于题目中说明了这种喜欢关系只存在于男女之间,因此可以大胆的拆点构图,因为男的喜欢的必定是女的,而女的之间不可能存在边(喜欢关系)。最大独立子集=顶点数-最大匹配数。由于是拆点构图,需要对最后的结果除以2。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <iostream>#include <algorithm>using namespace std;int N, matc 阅读全文
posted @ 2013-04-07 10:46 沐阳 阅读(285) 评论(0) 推荐(0)
摘要:题意:有一块土地,某些地方被挖去了,现在允许以每相邻的两块进行出售,问最多能出售多少块出去。解法:其实相邻即曼哈顿距离为1,那么最经典的方式当然是黑白染色棋盘来进行构图了,但是这题数据量太大了,虽然知道会MLE或者TLE,不过还是写了一遍。正确的解法当然是把所有的合法的点抠出来,题目已经告诉我们这样的点不会超过50个,所以不用当心任何问题,然后就是枚举两两组合是否相邻进行构图,然后求出最大匹配出售。这个枚举过程其实也是将图进行了拆点处理,曼哈顿距离为1的组合方式确保了从一点连出去的边的另一端点内部曼哈顿距离一定不为1,所以拆点后仍可以将坐标和为奇数的点看做X部,坐标和为偶数的点看做Y部,所不同 阅读全文
posted @ 2013-04-07 10:24 沐阳 阅读(327) 评论(0) 推荐(0)
摘要:题意:给定一些学生和课程的关系,问是否每一门课程能唯一对应一个学生。解法:每一条边对应一个选择关系,问题就是求一个完备匹配是否存在。代码如下:#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;int P, N;char G[105][305], vis[305];int match[305];bool path(int u) { for (int i = 1; i 阅读全文
posted @ 2013-04-07 09:23 沐阳 阅读(263) 评论(0) 推荐(0)
摘要:以前在杭电上做过,不过代码提交到POJ就WA了,原因还是程序存在一定的bug:http://www.cnblogs.com/Lyush/archive/2012/03/28/2422060.html在处理开始状态为0状态,匹配结果不进行统计的过程中,正确的处理方式应该是忽略掉所有能够工作的0状态的所有工作,因为这样的工作肯定是先让他们在0状态工作完。然后将其他的工作进行连边,然后求一个最大顶点覆盖(所有的边都至少有一个顶点落在所求顶点集合内),也即所有的工作至少能够有一台机器进行执行。代码如下:#include <cstdlib>#include <cstring>#i 阅读全文
posted @ 2013-04-07 09:03 沐阳 阅读(240) 评论(0) 推荐(0)
摘要:题意:给定一个方格,格子中的每点由空地,草地和墙组成,每个空地可以放置一个机器人,每个机器人能够向四个方向扫射激光,所以要给定一种方案能够在棋盘上放置足够多的机器人。激光可以穿过草地但是不能够穿过墙。解法:这题其实就是经典的二分匹配构图题,做法是将行和列进行拆分,也即如果某一行中有一堵墙,那么将墙前面和后面视为不同的一行,对列进行同样的处理,那么每个空地就需要获得一个新的行和列属性,通过遍历整个图来给每一块空地分配一个行和列号。分配要尽可能的紧凑。对于任何一块空地,要占用一个行和一个列(意味着该行和该列内不能够再容下其他空地)对于每一块空地,将其所对应的行号和列号分为图两个部分,构成二分图。二 阅读全文
posted @ 2013-04-03 10:31 沐阳 阅读(341) 评论(0) 推荐(0)
摘要:题意:给定一个棋盘,如果在某一个点放置棋子,那么这个棋子出现的行和列都不够有其他的棋子,除非他们之间有墙相隔。现在给定一个含有墙的和空地的棋盘,问最多能够放置多少棋子。解法:将所有为"."的点保存起来,如果两个点不在同一行且不在同一列,那么在两个点之间连一条边,否则判定两点之间是否有墙相隔,有的话连边,否则不连,最后求一个最大团即可。代码如下:#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>using namespace std;i 阅读全文
posted @ 2013-04-02 22:37 沐阳 阅读(197) 评论(0) 推荐(0)
摘要:题意:给定一个邻接矩阵,求最大团。解法:直接AC。代码如下:#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>using namespace std;int N, mp[55][55];int ret, st[55], cnt[55];void dfs(int x, int num) { int flag; for (int i = x+1; i < N; ++i) { if (!mp[x][i] 阅读全文
posted @ 2013-04-02 21:05 沐阳 阅读(309) 评论(0) 推荐(0)
摘要:题意:给定一个图,现在要给这个图上色,要求相邻的元素不能够涂上同样的颜色,一共只有两种颜色,黑色和白色。问给定的图最多能够涂上黑色点。解法:从相邻的点不能够涂上相同的颜色我们可以得出该题的实质就是要求一个最大的点独立集,而求一个图的点独立集如果所给的图是一棵树的话,就可以通过拆点转化为二分图来解了,由于给定的图很可能成环,因此化作二分图的做法在这里不再适应。另一个对应的问题就是通过对原图建一个反图,然后对反图做一个最大团的求解,最大团保证了是反图中的最大完全子集,任何两个元素之间都有边相连,反应在原图中则是任意两两之间不存在边,也就是两两不相邻,这刚好契合的题意。这是一个最简单的球最大团的版本 阅读全文
posted @ 2013-04-02 15:04 沐阳 阅读(708) 评论(0) 推荐(0)
摘要:题意:给定一个方格,然后告诉你一些规则,这些规则下方格中的有些位置是相冲突的。问在方格中最多能够放置多少个士兵。分析:比赛时一开始就想着用状态压缩DP来搞,不过忘了相邻三行产生关系同样可以通过添加状态的维数来解,于是想着旋转45度之后再DP,这样就只有两行发生关系,不过写起来应该不太好写。后面就用二分匹配写了该题,结果一直WA,知道比赛之后才明白原来这题不能够进行拆点构图,因为从一个点引出去的边的端点相互之间是可以连边的,这就相当于一个成环了,而有环的图又怎么划分出两个内部没有边的二分图呢?其实拆点是用求树的最小路径覆盖的问题上的,这题显然不满足。正确的解法是状态压缩DP或者是求反建图的最大团 阅读全文
posted @ 2013-04-01 20:38 沐阳 阅读(1101) 评论(2) 推荐(0)
摘要:题意:破解一套1-6位长度密码的系统,寻找这样一个序列:对于N位的密码10^N+N-1长度的连续的长为N的串能够枚举完所有的密码。解法:构图之后直接dfs会超内存,因此需要使用栈来实现。调了很久。代码如下:#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;int N, mod, head[100005];int idx, lim, edge, top;int st 阅读全文
posted @ 2013-03-27 22:29 沐阳 阅读(292) 评论(0) 推荐(0)
摘要:题意:给定许多根棍子,这些棍子两头有不同的颜色,问是否能够存在这样一中组合方式使得所有的棍子首尾相连。解法:这题使用map处理字符串超时了,所以自己写了一个插值取模的字符串hash。只要判定图是否连通和度为奇数是否大于2个即可,不可能出现奇数个度为奇数的点。代码如下:#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>#include <map>#include <string># 阅读全文
posted @ 2013-03-27 09:19 沐阳 阅读(240) 评论(0) 推荐(0)
摘要:题意:给定一系列的单词,这些单词要使用类似与成语接龙的方式将他们连接起来,现在问是否存在这样一个通路。解法:为什么这种题目刚看起来总是像那个什么哈密顿回路呢?欧拉回路主要解决对边的遍历问题,因此我们需要将已知条件转移到边上的信息即可。对于一个单词acm,那么就连接一条从a到m的边,那么走这条边也就访问了这个单词。有向图判定是否存在欧拉路径的方法是:在保证图连通的情况下,所有点的入度等于出度或者是存在两个点,一个点入度比出度大1,另一个点出度比入度大1。代码如下:#include <iostream>#include <cstring>#include <cstdl 阅读全文
posted @ 2013-03-26 22:02 沐阳 阅读(484) 评论(1) 推荐(0)
摘要:题意:给定一个无向图的关系,判定是否存在一条从M点出发回到0点并且走遍所有边的通路,也即欧拉通路。解法:该题如果当出发点就为0点话就等效于是否存在欧拉回路了。欧拉通路的判定条件为:连通的无向图中,度为奇数节点的个数为0个或者是2个。由于该题限定了起点和端点,因此度为奇数的点只能够由两个,且为M和0。当M==0时,奇数节点个数为0个符合题意,此时将构成一条欧拉回路。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <iostream>#include <alg 阅读全文
posted @ 2013-03-26 21:04 沐阳 阅读(502) 评论(0) 推荐(0)
摘要:题意:完全符合树的重心:即找到一个点,其所有的子树中最大的子树节点最少.代码如下:#include <cstdlib>#include <cstring>#include <cstdio> #include <iostream>#include <algorithm>#define MAXN 20000using namespace std;//说白了这一题就是求一棵树的重心 int N, idx; // 说明有N个节点//由于节点较多,且数为稀疏图,因此采用邻接表的形式来存储struct Node { int x, next, cn 阅读全文
posted @ 2013-01-06 22:39 沐阳 阅读(849) 评论(0) 推荐(0)