随笔分类 -  图论——最短路&&K短路&&生成树问题

摘要:周冬的《两极相通——浅析最大最小定理在信息学竞赛中的应用》把方法讲的很详细了。几点:1、把平面图G*中每一个面抽象成对偶图G*中的点。2、平面图包含f个面,设边e分割fi, fj,则连边(fi, fj)。3、关于如何区分源点和汇点。可以先连接s和t,得到一个附加面。如下图s->4->7->t->s,s*放到附加面中,t*放到无边界的面中,加以区分。4、建好图后要把(s*, t*)这条边删掉。5、G的面数等于G*的点数,G*的点数等于G的面数6、G与G*边数相同 G*中的环对应G中的割一一对应如图:hdu 3780题意是求最小割。直接套网络流模板会TLE。转换成最短路模型 阅读全文
posted @ 2013-06-01 11:39 AC_Von 阅读(1456) 评论(0) 推荐(1) 编辑
摘要:题意是:给一些坐标点,如果两点之间的距离小于R,并且两点之间没有其他点,则这两个点保持连通,这样构成了一个图。问这个图中生成树的个数。因为数据量并不大,O(N^3)的建图没有问题。建好图以后就可以用kirchhoff矩阵计算生成树的个数,之所以写这道题的解题报告是因为在高斯消元解kirchhoff矩阵时,需要用到逆元。(a/b)% mod,如果a,b的范围很大,结果会有很大的误差,这里可以转换一下 b*x = 1(% mod)则x为b的逆元 (a/b)%mod = (a*x)%mod求逆元的过程就是解线性同余方程b*x ≡1(% mod)。详见代码:/*高斯消元的整个过程中不能出现负数*... 阅读全文
posted @ 2012-10-08 21:21 AC_Von 阅读(692) 评论(0) 推荐(0) 编辑
摘要:周冬的《生成树的计数及其应用》论文上讲到过生成树计数的问题。用到的是一个Kirchhoff矩阵,它是这样定义的:a、设一个度数矩阵D,当i == j时,Dij = (i这个节点的度数),否则Dij = 0;b、设一个连通性矩阵A,如果i 和j连通,则Aij等于i到j的边数,否则Aij等于0;Kirchhoff矩阵C = D - A;有了Kirchhoff矩阵这个工具,我们可以引入Matrix-Tree定理:对于一个无向图G,它的生成树个数等于其Kirchhoff矩阵任何一个n-1阶主子式的行列式的绝对值(可以用高斯消元解,线性代数没学好的面壁去。。。-_-!)。所谓n-1阶主子式,就是对于.. 阅读全文
posted @ 2012-10-06 11:14 AC_Von 阅读(461) 评论(0) 推荐(0) 编辑
摘要:当最短路变成二维,就会发生非常有意思的事情。。。问题:给出u v w,表示从u -> v(双向边)所耗的时间为w,又知道没经过一条边,获利为1(对于一天边可以来回走)。求从start到end点,获利至少为k时用的最小时间。。。如果没有那个k,这个问题直接就是st -> ed的最短路。spfa,dijkstra。。。等等现在可以设 dis[i][j]表示到从st到 i点经过边数为j 时的最短路。然后直接spfa,队列中的每个点保留两个值,节点号,和到这个节点的边数。const int N = 100010;const int M = 5024;struct node { int to 阅读全文
posted @ 2012-08-24 09:13 AC_Von 阅读(345) 评论(1) 推荐(0) 编辑
摘要:/*建图用的邻接表,复杂度O(E*logE)*/struct pnode { int num; int len; pnode() {} pnode(int a, int b) : num(a), len(b) {} bool operator < (const pnode tmp) const { return len > tmp.len; }};int dis[N];bool vis[N];int n;void bfs(int s) { priority_queue<pnode> q; q.push(pnode(s, 0)); ... 阅读全文
posted @ 2012-08-17 19:26 AC_Von 阅读(809) 评论(0) 推荐(0) 编辑
摘要:大概的思路是线封死一条边i -> j,再找i到j的最短路dis[i][j]。dis[i][j] + w[i][j]就是一个环。找到所有环里的最小值就能得到最小环。不过。。。用dijkstra算单源最短路的话,这个的时间杂度是O(n^4);所以可以用floyd将时间复杂度控制在O(n^3)上。思路是在floyd算法进行松弛的时候就找这个最小环。ans = min(ans, dis[i][j] + w[i][k] + w[k][j]); 这样 k -> i - >.... -> j -> k就得到了一个最小环。具体实现如下:void dfs(int i, int j) 阅读全文
posted @ 2012-07-18 21:35 AC_Von 阅读(8152) 评论(0) 推荐(0) 编辑
摘要:又是生成树问题。。。次小生成树,顾名思义就是比最小稍微大那么一点点的生成树,^_^方法是:1、找到最小生成树,值为mst2、最小生成树种的点:找到每一个点到其它点的路径上的最大边权值 dp[i][j]表示i到j路径上的最大边权值3、加一条不在最小生成树上的边。比如i - k,同时删除在最小生成树上i -> k路径上最大的一个边权值dp[i][k]; 这样会得到 new_mst,在这些new_mst中找一个最小的,就是次小生成树的值实现上用到一些技巧,代码如下POJ 1679:View Code #include <iostream>#include <cstdio> 阅读全文
posted @ 2012-07-18 16:58 AC_Von 阅读(1601) 评论(0) 推荐(0) 编辑
摘要:定义:一个有向图,存在从某个点开始的到达所有的的一个最小生成树,则它就是最小树形图。从早晨到现在一直在翻资料,终于理解了一点。朱-刘算法的大概过程如下:1、找到除了root以为其他点的权值最小的入边。用In[i]记录2、如果出现除了root以为存在其他孤立的点,则不存在最小树形图。3、找到图中所有的环,并对环进行缩点,重新编号。4、更新其他点到环上的点的距离,如:环中的点有(Vk1,Vk2,… ,Vki)总共i个,用缩成的点叫Vk替代,则在压缩后的图中,其他所有不在环中点v到Vk的距离定义如下:gh[v][Vk]=min { gh[v][Vkj]-mincost[Vkj] } (1<=j 阅读全文
posted @ 2012-07-18 09:48 AC_Von 阅读(10288) 评论(0) 推荐(0) 编辑
摘要:首先这是要解决什么问题:一个带权完全图,每条边都有自己的花费值cost[i]和收益值benifit[i],如果用x[i]来代表一条边取或不取,那么求一个生成树。要求:r=(∑cost[i]*x[i] ) / (∑benifit[i]*x[i] )最小。经典题目:POJ2728 - Desert King如何来求解:这里用到了0-1分数规划思想,对于上式可以变形为 z(r)=∑cost[i]*x[i] -r*∑benifit[i]*x[i]。而z(r)=0为我们所求。这里有个非常重要的结论:z(r)为单调递减函数,因此是线性的。于是"我们可以兴高采烈地把z(r)看做以 cost[i]- 阅读全文
posted @ 2012-07-17 21:44 AC_Von 阅读(705) 评论(0) 推荐(0) 编辑
摘要:第一次接触A*,感觉好神奇。。启发函数:f(x) = g(x) + h(x);比如初始状态为s,目标状态为tg(x)表示从s到达状态x所消耗的代价h(x)表示从x到达t所估算的代价g'(x)表示s -> x可能出现的最小代价h'(x)表示x -> t可能出现的最小代价g(x) >= g'(x);h(x) <= h'(x);好吧,上面全是概念。。。当g(x) 为0时,A*就成了bfs,当h(x)为0时,A*就成了dfs。所以。。。启发函数的选择直接影响到A*算法的性能。大概的说说我对A*算法运算过程的理解吧:基本就是bfs形式,不过要用到优 阅读全文
posted @ 2012-07-17 10:06 AC_Von 阅读(4345) 评论(1) 推荐(0) 编辑
摘要:黑书+论文+各种资料。终于理解了一点。。。最小度限制生成树就是给一个图,让求它的最小生成树。找的的最小生成树满足并且点vo的度最大为k。算法流程如下:1.将该点(以下用v0表示)从图中删除,将得到m个连通分量。2.对每个连通分量求最小生成树,假设m个。3.从每个连通分量中找与v0关联的权值最小的边,与v0相连接,这样将得到v0的最小m度生成树4.如果 k < m 那么这种树是不存在的。5.如果 k >=m ,那么考虑构建 m+1度 最小生成树 ,将与v0关联的且不在当前的树中的边6.如果将其加入树中 ,必然会存在一个环,那么删掉该环中与v0不关联的权值最大边,将得到加入该边后的最小 阅读全文
posted @ 2012-07-03 21:50 AC_Von 阅读(1804) 评论(0) 推荐(1) 编辑
摘要:图算法差分约束系统的建立和求解poj1201(1716类似),poj2983, poj3159poj1275, poj1364最小(大)费用最大流poj2516, poj2195, poj3422(最大费用最大流)poj2135(很裸的最小费用最大流,不过有一个大坑。。。)双连通分量poj2942,poj3694强连通分支及其缩点poj2186, poj3592, poj3114图的割边和割点poj3352(外加3117)最小割模型poj3308, poj3155(偏难)详见:http://www.cnblogs.com/vongang/archive/2012/10/25/274004... 阅读全文
posted @ 2012-04-14 21:02 AC_Von 阅读(854) 评论(0) 推荐(0) 编辑
摘要:Bellman-Ford算法 Bellman-Ford可以用来解决含有负权图的单源最短路径(Dijkstra不能解决这种问题)。代码简单,但是效率低。具体的过程就是不停的松弛,每次松弛进行一次更新。如果更新n次仍然还可以更新,说明图中存在负环,直接跳出就可以。这种情况下无解。 Bellman-Ford的时间复杂度是O(ve).伪代码如下: 1 Bellman-Ford(G,w,s) :{ //图G ,边集 函数 w ,s为源点 2 for each vertex v ∈ V(G) do //初始化 1阶段 3 d[v]... 阅读全文
posted @ 2012-03-05 11:03 AC_Von 阅读(1886) 评论(0) 推荐(2) 编辑
摘要:这两天搞dp搞的快暴了,想学学网络流。拿过算导来一看,最短路还没整完呢。写了一个用并查集优化的kruskal算法,并查集是用非递归的状态压缩实现的。详见:http://www.cnblogs.com/vongang/archive/2011/07/31/2122763.html。kruskal没有用堆优化,不是我不想,而是实在不会。。。所以直接用sort按权值排了下序,时间复杂度O(n+n*logn)My Code:#include <iostream>#include <cstdio>#include <cstring>#include <algor 阅读全文
posted @ 2011-11-09 20:34 AC_Von 阅读(963) 评论(0) 推荐(0) 编辑
摘要:这题做的真的很想砸电脑!!!!TLE, 完了WA, 检查完错误又RE,无数次的RE,RE,RE,RE!!!RE你妹啊!把字符串定义在while()外边就能过,定义在里边就RE,还有char型能过,string就TLE,至于卡这么贱吗!!!前后总共来了30多遍!!!!崩溃啊!!!!!!#include <iostream>#include <cstdio>#include <string>#include <map>using namespace std;const int N = 108;const int inf = 0x3fffffff;ma 阅读全文
posted @ 2011-09-11 21:08 AC_Von 阅读(199) 评论(0) 推荐(0) 编辑
摘要:貌似是道水题。Prim, 484MS水过。。。#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N = 505;const int inf = 0x7ffffff;int dis[N][N];int low[N];int vis[N];int v[N];void Prim(int n){ int flag, i, j, min, sum = 0; for(i = 1; i <= n; i++) { low[i] = dis[1][i]; 阅读全文
posted @ 2011-09-09 19:52 AC_Von 阅读(228) 评论(0) 推荐(0) 编辑
摘要:这题A 的很是纠结,从下午5点多开始做到现在,一直WA。。。其中滋味,别提了。。。请容我发泄两句。。。1385!WA你妹啊!!!My Code:#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N = 105;const int inf = 10000000;int dis[N][N];int map[N][N];int low[N];int vis[N];int pre[N];int v[N];int cmp(int src, int de 阅读全文
posted @ 2011-09-08 22:16 AC_Von 阅读(334) 评论(0) 推荐(0) 编辑
摘要:个人感觉这个题挺好,用到了 最短路+DP,题意很容易就看出来了,其实就是0-1背包问题,状态转移方程:dp[j] = min(dp[j], dp[j-v[i]] + w[i]), 背包容量V = sum(v[0]+v[1] +...+v[n]},]其中每点的power为v[i], 0点到i点的最短路为w[i];然后再在i = [sum/2+1, sum]范围内找min(dp[i])。 ps:偶悲剧的把i的范围写成i = [sum/2, sum]了,贡献无数WA。。。郁闷!!!My Code:#include <iostream>#include <cstdio>#inc 阅读全文
posted @ 2011-09-07 16:32 AC_Von 阅读(227) 评论(0) 推荐(0) 编辑
摘要:开始用Floyd做的,TLE!更二的时我自己找了一组1 1000 的数据,4S才算出来,本身程序就有问题,我居然还交上去了。。。后来用Dijkstra做,过了。。。200+ms;#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N = 1005;const int inf = 1000000;int dis[N][N];int low[N];int vis[N];int num1[N];int num2[N];void Dijkstra(in 阅读全文
posted @ 2011-09-07 11:10 AC_Von 阅读(221) 评论(0) 推荐(0) 编辑
摘要:把与某个楼成相连的上下楼层为边建立一个图,边的权值为1.如:3 3 1 2 5可建成图:map[1][4] = 1;map[2][5] = 1;map[3][2] = 1;map[3][4] = 1;map[4][2] = 1;然后用最短路经的解法Floyd, Bellman_Ford, SPFA, Dijkstra...这里用的是Dijkstra解法My Code:#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int inf = 1000000 阅读全文
posted @ 2011-08-16 21:00 AC_Von 阅读(362) 评论(0) 推荐(0) 编辑