随笔分类 -  图论相关

摘要:题意:该题的题意晦涩,勉勉强强听别人说了一遍后再读了一遍题才算懂了题意,题图说的是A国因为B国药进攻自己的国家,于是想办法在联通A-B之间的路径上进行阻击。阻击的舰船停留在一个路径上,舰船上都要放置水晶,相同水晶的舰船可能会被一次性摧毁,于是现在要求给出尽可能多的方案来部署舰船,使得同一水晶的舰船能够阻断所有从B到A的路径,每条路径上只能够部署一部舰船。分析:题意抽象之后就是一个网络求出从源点到汇点的尽可能多的割边集,且每个割边集没有公共边。根据题目的要求,我们设想从A到B的最短路长度为K,那么假设方案数大于K,那么每个割边集至少要包含该最短路上的一条边,否则存在从A到B的通路,那么这个包含的 阅读全文
posted @ 2013-07-22 10:01 沐阳 阅读(399) 评论(0) 推荐(0) 编辑
摘要:题意:给定一个图,求从1到N的递增边权的最短路。解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每次将相同权值的边全部取出来一同更新,每条边能够更新的前提是某一个端点在之前被更小的边权更新过。另外一个要注意的地方就是一次相同边的更新中,要把所有的更新暂存起来最后一起去更新,这样是为了防止同一权值的边被多次加入到路径中去。代码如下:#include <cstdlib>#include <cstdio>#include <algorithm>#include &l 阅读全文
posted @ 2013-06-08 19:20 沐阳 阅读(719) 评论(0) 推荐(0) 编辑
摘要:题意:给定一棵树,然后给定若干组询问,问某些点被作为最近公共祖先的次数。解法:刚刚一直不知道根在哪里给了出来,后来才发现给定的点一定是按照从层数低的节点指向层数高的节点,因此没有双亲的节点为根节点,然后运行tarjan算法即可。这里刚开始的时候我还想把最后的结果除以2输出,这里没有这个必要,因为两个节点一定有一个先后的遍历顺序,这个顺序保证了只被统计一次。代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#include <algorithm>#include <iostre 阅读全文
posted @ 2013-05-17 16:31 沐阳 阅读(273) 评论(0) 推荐(0) 编辑
摘要:题意:给定N个节点一棵树,现在要求询问任意两点之间的简单路径的距离,其实也就是最短路径距离。解法:spfa:直接对每一对点作一次spfa即可。Tarjan:求出两个点A,B之间的最近公共祖先C,设根到每个点的最短距离为dis[],那么距离就是dis[A]+dis[B]-2*dis[C]。而根到各个点的距离一次dfs就出来了,因此问题转化为求出两点之间的最近公共祖先,Tarjan算法能够离线解决所询问的点对。原理如下:对于一次dfs,当第一次遍历到点u时,那么令set[u] = u。遍历完以u为根的树后,将u所属集合指向双亲节点。接下来查看u的访问列表中有没有询问<u, v>的点对, 阅读全文
posted @ 2013-05-17 15:34 沐阳 阅读(339) 评论(0) 推荐(0) 编辑
摘要:http://wenku.baidu.com/view/56c85dfafab069dc502201a3.html一道非常经典的割的应用。 阅读全文
posted @ 2013-05-06 16:46 沐阳 阅读(188) 评论(0) 推荐(0) 编辑
摘要:题意:给定若干个房间,现在这些房间之间能够相互的联通,房间门是单向的,现在问一些门中都有人的情况下,至少要堵住多少条门才能够使得无法到达终点。解法:显然这是一个集合的分割问题,即求这样的一个割:使得终点房间与某些存在人的房间的一个分割,题中求的最少的人就是求解一个最小割。将问题转化为网络流求解。通过建立从超级源点到存在人的一些房间,那么从汇点反向遍历寻找这样的一个割。如果从源点到有人房间的边满流,那么反向遍历一定不会将这个节点划分到汇点集合里面去,如果该边不满流的话,如果划分到了汇点集合,则表明存在从源点到汇点的流量,于最大流相悖。因此所求既满足题意。代码如下:#include <cst 阅读全文
posted @ 2013-05-06 16:16 沐阳 阅读(364) 评论(0) 推荐(0) 编辑
摘要:题意:给定N个点,M条边,每个点为0或者为1,每条边有一个权值。接下来有Q组操作,要么翻转某个点的标号,要么询问某组边的权值一共为多少,总共有三种类型的边:端点分别为(0, 0), (0, 1), (1, 1)。解法:这题的一个蛮力的解法就是记录好每一点的标号,然后O(1)的时间修改编号,对于每次查询就遍历所有的边进行询问。这样的话时间复杂度就是O(q*m)了,显然无法接受。换个好点的,我们首先通过原始数据在输入的时候处理一下,保留好每条边所属的类型。那么在没有点进行修改的话,O(1)时间进行输出。问题就是如果要进行修改的话,一个合理的方式就是修改当前节点所连的边的属性,因为其他于该节点无关的 阅读全文
posted @ 2013-05-02 22:12 沐阳 阅读(1018) 评论(0) 推荐(0) 编辑
摘要:题意:给定一个无向图,要求判定分离两个点的最小割是否唯一。解法:在求出最大流的基础上,从源点进行一次搜索,搜索按照未饱和的边进行,得到顶点子集S的顶点个数;再从汇点反向搜索未饱和的边,得到子集T的顶点个数,判定顶点数相加是否等于总共的顶点数。http://blog.csdn.net/waitfor_/article/details/7330437的文章写的很好,这里截取文中所画的两个图进行说明。(1)正向搜索集合为S,反向搜索集合为T,cnt1和cnt2都是最小割边。很显然M还存在着最小割边,因为从M到T的残余网络也没有流向T的容量了。(2)增加E1这部分边的容量将直接导致网络最大流量增加。增 阅读全文
posted @ 2013-05-01 21:33 沐阳 阅读(1449) 评论(0) 推荐(0) 编辑
摘要:题意:给定一系列的单词要求按照字典序把他们全部输出来。解法:首先判定能不能构成欧拉回路,然后就是O(E)的dfs计算出来。这题使用Fleury模板没搞出来,原因这里要根据单词来走边,而该算法得到的是节点访问序列。后面看到一种dfs,既能够保留边又能够保留点又简单多了,以后果断专注这种写法。代码如下:#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#include <string>#include <vector>#incl 阅读全文
posted @ 2013-04-24 15:00 沐阳 阅读(412) 评论(0) 推荐(0) 编辑
摘要:题意:对于一个长度为2^N的循环序列,从某一个位置开始依次取N个,这样就能够生成2^N个序列,现在要求输出一个最小的满足要求的循环序列。输出这个序列生成的第K个数字是多少?解法:套用Fleury算法,构边的时候保持从小到大的顺序即可。如果是生成N为序列的话,就考虑前N-1位构成的节点相互的连的边(例如三位数就可以这样构边 00 --> 01 --> 11那么这两条边就代表生成了001和011这两个数字),输出欧拉回路即可。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#incl 阅读全文
posted @ 2013-04-23 18:25 沐阳 阅读(537) 评论(0) 推荐(0) 编辑
摘要:上面是摘自图论书上的定义。算法在运行过程中删除了所有已走的路径,也就是说途中残留了所有没有行走的边。根据割边的定义,如果在搜索过程中遇到割边意味着当前的搜索路径需要改进,即提前输出某一个联通子集的访问序列,这样就能够保证访问完其中联通子图中后再通过割边访问后一个联通子图,最后再沿原路输出一开始到达该点的路径。如果只有割边可以扩展的话,只需要考虑先输出割边的另一部分联通子集访问序列。样例图:代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <iostream>#in 阅读全文
posted @ 2013-04-22 21:29 沐阳 阅读(21634) 评论(2) 推荐(5) 编辑
摘要:题意:给定一个进行了集合划分的序列,现有一套标准答案,同样给定了M个非标准答案,现在要计算这M个非标准答案的最大正确率为多少?解法:该题考虑的是可以采用不同的字符进行相同的划分。那么求解的就是一个集合符号的匹配的问题,采用何种的集合符号一一对应才能使得正确率最高。那么对于每对应某个位置的集合标号,我们可以假设是对应的,那么在这个基础上再进行更多的匹配,建立起x字符对应y字符最多能够对多少个的一个边,然后调用KM算法即可。在读取数据的时候使用gechar死活过不了(会读到非字母导致RE,可能是数据中有多个空格或者...),还好有cin这个利器,不过就是速度慢了点。代码如下:#include &l 阅读全文
posted @ 2013-04-17 17:59 沐阳 阅读(411) 评论(0) 推荐(0) 编辑
摘要:题意:给定一系列的匹配关系,现在有些匹配时不允许的,问最大匹配时多少。解法:解决问题的办法就是在计算松弛d值的时候,如果d的值在经过一次可行标的更新后仍然不能得到某个最小值来扩充原图的边集。那么就不存在一个最优权值匹配。注意当值为负的时候就不能够匹配。代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int INF = 0x3f3f3f3f; 阅读全文
posted @ 2013-04-17 10:57 沐阳 阅读(224) 评论(0) 推荐(0) 编辑
摘要:题意:这题自己YY了下,没想到结论还是对的。题目告诉我们一个有向图,现在问将图中的每一个点都划分到一个环中的最少代价是多少?每条边都有一个代价。解法:由于要成环,那么将这个图进行拆点,就变成了单向的二分图了,此时一个完备匹配就是一种连线策略,只要保证没有边是和自己相连,就能够满足题目中要求的每个点至少属于一个环。证明也是很简单的。因为我们总可以从一个完备匹配中找出起点,然后再从匹配点作为起点找......左图可以看做是1,2成环,3,4,5成环。代码如下:#include <cstdlib>#include <cstring>#include <cstdio> 阅读全文
posted @ 2013-04-16 22:22 沐阳 阅读(1033) 评论(0) 推荐(0) 编辑
摘要:题意:给定一个二分图,N个点对应M个点,两两之间存在一组关系,每组关系一个权值。题目中了给定了一个匹配方案,现在要求满足这组关系中的最大的匹配权值在原方案上增长了多少?并且还要求求出在原匹配方案上改变最少多少条边能够得到这个最大匹配?解法:该题求增加了多少匹配值非常好算,问题就是这个最少改变多少条边。前面做过一道题目使用dfs遍历出所有的最优匹配情况,果断用在这里超时,主要原因是点过多,当然还有就是最大匹配不太好剪枝。想了许久硬了没有法子。百度......正确的解法真他妈犀利,主要思想就是增加原配边的权值,而且又不会对结果造成影响。这听起来似乎是不太可能的,但是确实有办法能够办到。首先由于顶点 阅读全文
posted @ 2013-04-16 19:06 沐阳 阅读(963) 评论(0) 推荐(0) 编辑
摘要:题意:此乃第一道真正意义上的最大权值匹配,其他题目其实都是求一个最小权值匹配。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <iostream>#include <algorithm>using namespace std;const int INF = 0x3f3f3f3f;int N;int w[305][305];int lx[305], ly[305];int sx[305], sy[305];int match[305], slack[3 阅读全文
posted @ 2013-04-16 18:14 沐阳 阅读(217) 评论(0) 推荐(0) 编辑
摘要:题意:给定平面上两类同样多的点,要求输出一种方案使得所有匹配的点的连线两两不相交。解法:考虑到下面的一般情况:可以很容易的证明两条交叉边的距离和一定大于两条不交叉的距离和,因此问题转化为只要原图中存在交叉边,那么就可以找到更小的匹配的方式使得总距离更小。使用KM算法求出最小权值匹配输出匹配方案即可。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>#include <iostream>#include <cmath>u 阅读全文
posted @ 2013-04-16 16:13 沐阳 阅读(422) 评论(0) 推荐(0) 编辑
摘要:题意:给定两个关系矩阵,分别表示雇主和雇员的相互好感度,好感度为1最优,N最差。如果一个人与好感度为P的人匹配的话,差值为P-1,现在要求是的总共的差值最小的匹配方法,并且输出所有的匹配方案。解法:将两两关系矩阵转化为边上的权值,然后进行一次最大匹配,最后dfs枚举输出结果,数据中给的矩阵上下颠倒了。代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cmath> 阅读全文
posted @ 2013-04-10 23:04 沐阳 阅读(348) 评论(0) 推荐(0) 编辑
摘要:做这题的时候突然觉得每次修改一次可行标就一定能够找到增广路,因此把while(1)改成了int T = 2; while(T--) {}谁知道WA了,这就比较纠结了,后面手动模拟了一组数据才知道不在交错树的点不一定不在已经存在的匹配中,增加的可行边右端点可能就落在了一条匹配边上,那么这样一来并不能保证找到一条增广路。这样也就解释了为什么对于slack[]数组每次进行一个更新,因为这个值由于循环次数的增加可能多次被利用到,没有找到增广路,那么原来的那条交错树一定还会边遍历一遍,而且会有新的节点加入到S和T集合(其实反正都会遍历一遍,那么不更新slack数组,dfs过程中也会自动缩小)。题意:有N 阅读全文
posted @ 2013-04-10 07:53 沐阳 阅读(367) 评论(0) 推荐(0) 编辑
摘要:题意:给定一个网格图,图上有一些人要到一些房子当中去,人和房子的数量一样多,人和房子的曼哈顿距离作为行走的开销,问所有人走到房子中的最小开销。解法:将人和房子之间两两之间建立带权边,权值为曼哈顿距离的相反数,这样问题就转化为最大权值匹配问题。代码如下:#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int INF = 0x3f3f3f3f;int N 阅读全文
posted @ 2013-04-09 19:40 沐阳 阅读(285) 评论(0) 推荐(0) 编辑

点击右上角即可分享
微信分享提示