算法作业
近期算法布置了一篇课设,在这里描述一下,并晒一下代码。整体来说算法实验很简单,实现方法也很简单粗暴,不过练习一下图的写法吧。
(PS.博主使用的是eclipse for C++,可以利用debug纠错)
问题描述
- 生成100个点,500条边的有向图,任选一点为源点,计算s到其它点的距离。(用邻接链表存储)
- 将上述有向图变成dag图,从中去掉一些边,不允许使用递归
- 计算上述dag图中最长路径,并记录下路径
问题一
生成100个点,500条边的有向图,任选一点为源点,计算s到其它点的距离。(用邻接链表存储)
问题分析
因为需要用邻接链表存储,因此需要用一个链表结构,基本结构如下:
1 | struct node{ |
这里,我写的node的性质比较多,但是事实上是完全没有必要的,如我的小伙伴就只存了一个id,后来证明她这种做法更为合理。
下面需要考虑建一个图需要什么样的方法,由于博主之前写过后缀树一类的,因此这个还是很easy的,
1 | class Arithmex1 { |
下面开始图的主要代码:
create方法:
1 | bool Arithmex1::create(){ |
insertEdge方法(简单的,链表插入的方法):
1 | bool Arithmex1::insertEdge(int a,int b){//插入边 |
博主为了方便,写的方法比较粗暴,因此只是作为参考。值得注意的是,当我们以node来表示节点时,节点在存储空间内不止有一个。如下图:数组中有一个1,链表中2/4后也均有1,因此就像上面说的,在node struct中增加属性没有必要,且可能浪费空间,这时候一个好的做法是维护一个同等规模的数组来保存节点的属性
下面是需要计算源点s到图中各点的距离,显然可以用BFS,主要思路是维持一个数组存储长度,子节点的长度是父节点长度+1;
1 | int Arithmex1::distance(int i){ |
问题二
将上述有向图变成dag图,从中去掉一些边,不允许使用递归
问题分析
这里的一个简单思路就是删除返回边。根据《算法导论》上的算法描述,即dfs时遇到灰色节点,边可被删除。难点主要在于白色、黑色、灰色(也可以是开始时间、结束时间)的判定。另一个难点在于不允许使用递归。这里面有很多种情况,需要仔细判定。
1 | void Arithmex1::dfs(int start){ |
因为有的节点入度=0,即一次dfs会忽视它们,因此可以采用直接遍历的方法
1 | void Arithmex1::dag(){ |
问题三
计算上述dag图中最长路径,并记录下路径。
问题分析
看到这个题,第一感觉是用拓扑序列,因为拓扑头一定是头结点。
但是博主又想偷懒了,拓扑头怎么求?在上文中,我们已经求出了结束时间最晚的那个节点,无疑一定是拓扑头。但是这里,博主直接采用的入度为0的为拓扑头,(再维持一个数组添加入度属性啦,插入边入度+1,删除边入度-1),这里,只要从拓扑头开始bfs(注意,这里让求的是最长路径,因此无需判断bfs时此点有没有访问过,而且是有向无环图,所以不会死循环)
这是一种比较简单的思路,却需要大量空间时间,另一种比较好的方法是完全用拓扑序列来实现。至于一些细节就不再赘述,代码如下:
1 | int Arithmex1::maxdis(){ |
更多完整代码参见https://github.com/yongbosmart