Graph Theory Algorithms

  1 /**
  2  * 图论
  3  **/
  4
  5  /***************************** 图的抽象数据类型 ************************************/
  6 ADT Graph
  7 {
  8     数据:
  9     Graph = (Vertex, Edge)是可以用不同方式存储的图,Vertex是顶点集,
 10     Edge = {<vertex_1, vertex_2> | vertex_1, vertex_2属于Vertex,vertex_1不等于vertex_2,<vertex_1, vertex_2>表示连接vertex_1和vertext_2的边}
 11
 12     操作:
 13     void InitGraph(Graph &graph, int vertextCount, bool directed);// 按顶点个数vertexCount和有向标志directed构造图graph
 14     void DestroyGraph(Graph &graph);                                     // 清楚原有的图graph
 15     bool IsDirected(Graph &graph);                                       // 判断图graph是否是有向图
 16     int  VertexCount(Graph &graph);                                      // 求出并返回图graph的顶点数
 17     int  EdgeCount(Graph &graph);                                        // 求出并返回图graph的边数
 18     int  FirstAdjoinVertex(Graph &graph, Vertex vertex);          // 返回vertex的第一个邻接顶点,若vertex没有邻接点,则返回-1
 19     int  NextAdjoinVertex(Graph &graph, Vertex vertex_1, Vertex vertex_2);  // 返回vertex_1的下一个邻接点(相对于vertex_2)
 20     void Insert(Graph &graph, Vertex vertex_1, Vertex vertex_2);            // 在图中插入边<vertex_1, vertex_2>
 21     void Delete(Graph &graph, Vertex vertex_1, Vertex vertex_2);            // 在图中删除边<vertex_1, vertex_2>
 22     bool EdgeExisting(Graph &graph, Vertex vertex_1, Vertex vertex_2);   // 判断边<vertex_1, vertex_2>是否是图graph的边,                                                                                       若是,返回true,否则返回false
 23     void Traverse(Graph &graph, Vertex vertex, *Visit());// 从顶点vertex开始遍历graph,对每个顶点调用函数Visit(),Visit()因遍历方法而异
 24 }
 25
 26 struct Graph
 27 {
 28     int  vertextCount;             // 图的顶点数
 29     int  EdgeCount;                // 图的边数
 30     bool directed;                 // 有向图和无向图的标志
 31     bool *adjoinMatrix;            // 指向邻接矩阵的指针
 32     bool *visited;                 // 顶点是否被访问过的标志
 33 };
 34
 35 /****************************** 图的邻接矩阵表示 ***********************************/
 36 /**
 37  * 下面表示的是无权图的基本操作的实现(带权图的操作实现类似)
 38  **/
 39 /**
 40  *    图的初始化操作
 41  **/
 42 void InitGraph(Graph &graph, int vertextCount, bool directed)
 43 {
 44     graph.vertextCount = vertextCount;                                // 初始化顶点数
 45     graph.EdgeCount = 0;                                              // 初始化边数为0
 46     graph.directed = directed;                                        // 设置有向图和无向图的标志
 47     graph.adjoinMatrix = new bool[vertextCount * vertextCount];       // 为邻接矩阵分配内存空间
 48     graph.visited = new bool[vertextCount];                           // 为顶点访问标志数组分配内存空间
 49     for(int out = 0; out < vertextCount; ++out) {
 50         for(int in = 0; in < vertextCount; ++in)
 51             graph.adjoinMatrix[out * vertextCount + in] = false;      // 初始化邻接矩阵
 52         graph.visited[out] = false;                                   // 初始化顶点访问标志
 53     }
 54 }
 55
 56 /**
 57  * 清除图的操作
 58  **/
 59 void DestroyGraph(Graph &graph)
 60 {
 61     delete [] graph.adjoinMatrix;        // 清除图的标志
 62     delete [] graph.visited;             // 清除标志数组
 63     graph.vertextCount = 0;              // 置顶点数为0
 64     graph.EdgeCount = 0;                 // 置边数为0
 65 }
 66
 67 /**
 68  * 图graph的顶点数统计
 69  **/
 70 int  VertexCount(Graph &graph) { return graph.vertextCount; }
 71
 72 /**
 73  * 图graph的边数统计
 74  **/
 75 int  EdgeCount(Graph &graph) { return graph.EdgeCount; }
 76
 77 /**
 78  * 判断图graph是否是有向图
 79  **/
 80 bool IsDirected(Graph &graph) { return graph.directed; }
 81
 82 /**
 83  * 判断边<vertex_1, vertex_2>是否是图graph的边,若是,返回true,否则返回false
 84  **/
 85 bool EdgeExisting(Graph &graph, Vertex vertex_1, Vertex vertex_2)
 86 {
 87     return graph.adjoinMatrix[vertex_1 * graph.vertextCount + vertex_2];
 88 }
 89
 90 /**
 91  * 在图中插入边<vertex_1, vertex_2>
 92  **/
 93 void Insert(Graph &graph, Vertex vertex_1, Vertex vertex_2)
 94 {
 95     if(graph.adjoinMatrix[vertex_1 * graph.vertextCount + vertex_2] == false)
 96         ++graph.EdgeCount;                                                              // 要添加的边不存在,边数加1
 97     graph.adjoinMatrix[vertex_1 * graph.vertextCount + vertex_2] = true;                // 添加边<vertex_1, vertex_2>
 98     if(!graph.directed)
 99         graph.adjoinMatrix[vertex_2 * graph.vertextCount + vertex_1] = true;            // 如果是无向图,处理对称元素
100 }
101
102 /**
103  * 在图中删除边<vertex_1, vertex_2>
104  **/
105 void Delete(Graph &graph, Vertex vertex_1, Vertex vertex_2)
106 {
107     if(graph.adjoinMatrix[vertex_1 * graph.vertextCount + vertex_2] == true)
108         --graph.vertextCount;                                                            // 要添加的边存在,边数减1
109     graph.adjoinMatrix[vertex_1 * graph.vertextCount + vertex_2] = false;                // 删除边<vertex_1, vertex_2>
110     if(!graph.directed)
111         graph.adjoinMatrix[vertex_2 * graph.vertextCount + vertex_1] = false;            // 如果是无向图,处理对称元素
112 }
113
114 /**
115  * 返回vertex的第一个邻接顶点,若vertex没有邻接点,则返回-1
116  **/
117 int  FirstAdjoinVertex(Graph &graph, Vertex vertex)
118 {
119     int tempVertex = 0;
120     while((tempVertex < graph.vertextCount) && (graph.adjoinMatrix[vertex * graph.vertextCount + tempVertex] == false)) {
121         ++tempVertex;
122     }
123     if(tempVertex == graph.vertextCount)
124         return -1;                                // 未找到邻接顶点
125     else
126         return tempVertex;                        // 返回邻接顶点
127 }
128
129 /**
130  * 返回vertex_1的下一个邻接点(相对于vertex_2)
131  **/
132 int  NextAdjoinVertex(Graph &graph, Vertex vertex_1, Vertex vertex_2)
133 {
134     int tempVertex = vertex_2 + 1;
135     while((tempVertex < graph.vertextCount) && (graph.adjoinMatrix[vertex * graph.vertextCount + tempVertex] == false)) {
136         ++tempVertex;
137     }
138     if(tempVertex == graph.vertextCount)
139         return -1;                                // 未找到邻接顶点
140     else
141         return tempVertex;                        // 返回邻接顶点
142 }
143
144
145 /***************************** 图的邻接表表示表示 ***********************************/
146 // 结点抽象类型定义
147 struct GraphNode
148 {
149     int vertex;                                                                            // 顶点
150     GraphNode *next;                                                                       // 指向边的终端结点的指针
151     GraphNode(int tempVertex, GraphNode *pointer) { vertex = tempVertex; next = pointer; } // 构造函数
152 };
153
154 typedef GraphNode *GraphLink;
155
156 // 邻接表的结构声明
157 struct Graph
158 {
159     int  vertextCount;                // 图的顶点数
160     int  edgeCount;                   // 图的边数
161     bool directed;                    // 有向图/无向图的标志
162     bool *visited;                    // 顶点是否被访问过的标志
163     GraphLink adjoinMatrix;           // 单链表的表头定义
164 };
165
166 /**
167  *    图的初始化操作
168  **/
169 void InitGraph(Graph &graph, int vertextCount, bool directed)
170 {
171     graph.vertextCount = vertextCount;                           // 初始化顶点数
172     graph.EdgeCount = 0;                                         // 初始化边数为0
173     graph.directed = directed;                                   // 设置有向图和无向图的标志
174     graph.adjoinMatrix = new GraphLink[vertextCount];            // 为邻接矩阵分配内存空间
175     graph.visited = new bool[vertextCount];                      // 为顶点访问标志数组分配内存空间
176     for(int index = 0; index < vertextCount; ++index) {
177         graph.adjoinMatrix[index] = new GraphNode(index, NULL);  // 初始化单链表表头,结点值为index,指针域为空
178         graph.visited[index] = false;                            // 初始化顶点访问标志
179     }
180 }
181
182 /**
183  * 清除图的操作
184  **/
185 void DestroyGraph(Graph &graph)
186 {
187     for(int index = 0; index < graph.vertextCount; ++index) {     // 一次销毁各单链表
188         GraphLink link = graph.adjoinMatrix[index];
189         while(link) {
190             GraphLink tempLink = link;
191             link = link->next;
192             delete tempLink;
193         }
194     }
195     delete [] graph.visited;            // 清除标志数组
196     graph.vertextCount = 0;             // 置顶点数为0
197     graph.EdgeCount = 0;                // 置边数为0
198 }
199
200 /**
201  * 图graph的顶点数统计
202  **/
203 int  VertexCount(Graph &graph) { return graph.vertextCount; }
204
205 /**
206  * 图graph的边数统计
207  **/
208 int  EdgeCount(Graph &graph) { return graph.EdgeCount; }
209
210 /**
211  * 判断图graph是否是有向图
212  **/
213 bool IsDirected(Graph &graph) { return graph.directed; }
214
215 /**
216  * 判断边<vertex_1, vertex_2>是否是图graph的边,若是,返回true,否则返回false
217  **/
218 bool EdgeExisting(Graph &graph, Vertex vertex_1, Vertex vertex_2)
219 {
220     GraphLink link = graph.adjoinMatrix[vertex_1]->next;            // 根据起始点确定链表
221     while(link) {
222         if(link->vertex == vertex_2)                                // 边存在
223             return true;
224         else
225             link = link->next;                                      // 寻找下一条
226     }
227     return false;                                                   // 边不存在
228 }
229
230 /**
231  * 在图中插入边<vertex_1, vertex_2>
232  **/
233 void Insert(Graph &graph, Vertex vertex_1, Vertex vertex_2)
234 {
235     if(EdgeExisting(graph, vertex_1, vertex_2) == false) {      // 没有判断要添加的边是否存在
236         graph.adjoinMatrix[vertex_1]->next = new GraphNode(vertex_2, graph.adjoinMatrix[vertex_1]->next);
237         if(!graph.directed)
238             graph.adjoinMatrix[vertex_2]->next = new GraphNode(vertex_1, graph.adjoinMatrix[vertex_2]->next); // 若是无向图
239         ++graph.EdgeCount;                           // 边数加1
240     }
241 }
242
243 /**
244  * 在图中删除边<vertex_1, vertex_2>
245  **/
246 void Delete(Graph &graph, Vertex vertex_1, Vertex vertex_2)
247 {
248     GraphLink link = graph.adjoinMatrix[vertex_1];                // 取链表头
249     while(link->next) {                                           // 寻找待删除的边
250         if(vertex_2 == link->next->vertex) {                      // 找到要删除的边,执行删除操作
251             GraphLink tempLink = link->next;
252             link->next = tempLink->next;
253             delete tempLink;
254             break;
255         }
256         link = link->next;                                        // 指向下一个邻接顶点
257     }
258     if(graph.directed == true)                                    // 如果是有向图,则返回
259         return ;
260     link = graph.adjoinMatrix[vertex_2];                          // 去链表头
261     while(link->next) {                                           // 寻找待删除的边
262         if(vertex_1 == link->next->vertex) {                      // 找到要删除的边,执行删除操作
263             GraphLink tempLink = link->next;
264             link->next = tempLink->next;
265             delete tempLink;
266             break;
267         }
268         link = link->next;                                        // 指向下一个邻接顶点
269     }
270 }
271
272 /**
273  * 返回vertex的第一个邻接顶点,若vertex没有邻接点,则返回-1
274  **/
275 int FirstAdjoinVertex(Graph &graph, int vertex)
276 {
277     GraphLink link = graph.adjoinMatrix[vertex]->next;            // 取链表头
278     if(link)
279         return link->vertex;                                      // 返回第一个邻接顶点
280     else
281         return -1;                                                // 没有邻接顶点,则返回-1
282 }
283
284 /**
285  * 返回vertex_1的下一个邻接点(相对于vertex_2)
286  **/
287 int  NextAdjoinVertex(Graph &graph, Vertex vertex_1, Vertex vertex_2)
288 {
289     GraphLink link = graph.adjoinMatrix[vertex_1]->next;          // 取链表头
290     while(link) {
291         if(link->vertex == vertex_2 && link->next != NULL)        // 判断当前邻接顶点
292             return link->next->vertext;                           // 返回下一个邻接顶点
293         else
294             link = link->next;                                    // 指向下一个邻接顶点
295     }
296     return -1;                                                    // 未找到,返回-1
297 }
298
299 /**
300  * 图的深度优先遍历
301  **/
302 void DepthFirstTraverse(Graph &graph, int vertex)
303 {
304     graph.visited[vertex] = true;                                                    // 置访问标志
305     for(int tempVertex = FirstAdjoinVertex(graph); tempVertex != -1; ++tempVertex) { // 依次访问顶点vertex的邻接顶点
306         if(graph.visited[tempVertex] == false)                                       // 若顶点未访问,则递归调用
307             DepthFirstTraverse(graph, tempVertex);
308     }
309 }
310
311 /**
312  * 图的广度优先遍历
313  **/
314 void BreadthFirstSearch(Graph &graph, Vertex vertex)
315 {
316     CircleQueue circleQueue;                                    // 定义循环队列
317     InitQueue(circleQueue);                                     // 初始化循环队列
318     if(graph.visited[vertex] == false)                          // 是否没有访问过
319         graph.visited[vertex] = true;                           // 置访问标志,可插入顶点访问操作
320     EnQueue(circleQueue, vertex);                               // 顶点入队列
321     while(!IsEmpty(circleQueue)) {                              /* 循环直到队列为空 */
322         Vertex currentVertex;
323         DeQueue(circleQueue, &currentVertex);                   // 队列元素出队
324         for(Vertex tempVertex = FirstAdjoinVertex(graph, currentVertex); tempVertex != -1; tempVertex = NextAdjoinVertex(graph, currentVertex, tempVertex)) {
325             if(graph.visited[tempVertex] == false) {            // 是否没有访问过
326                 graph.visited[tempVertex] = true;               // 置访问标志
327                 EnQueue(circleQueue, tempVertex);               // 刚访问过的顶点元素入队
328             }
329         }
330     }
331     DestroyGraph(circleQueue);
332 }
333
334 /**
335  * 寻找图中从顶点vertex_1到顶点vertex_2的简单路径
336  * 基本思路:
337  *         对依附于顶点vertex_1的每条边<vertex_1, temp_1>,寻找从顶点temp_1到顶点vertex_2的一条简单路径,而且不经过vertex_1,
338  *        考虑依附于顶点temp_1的边<temp_1, temp_2>,寻找从顶点temp_2到顶点vertex_2的一条简单路径,并且不经过顶点vertex_1和
339  *        顶点temp_1,如此下去,直到找到解为止,所以这个问题可以利用深度优先遍历实现。
340  *        从顶点vertex_1出发做深度优先遍历,如果遇到顶点vertex_2,回溯就可以得到从顶点vertex_1到顶点vertex_2的一条路径。那
341  *        如何保证这是一条简单路径,方法是:维护一条路径,依次记录深度优先遍历过程中访问过的顶点;在深度优先遍历过程中,如果
342  *        顶点的所有邻接顶点都被访问过,仍然未能到达目标顶点vertex_2,则将此顶点从路径中删除;到达目标顶点后,就可以得到一条简单路径
343  **/
344 void SimplePath(Graph &graph, Vertex vertex_1, Vertex vertex_2)
345 {
346     graph.visited[vertex_1] = true;                                        // 设置访问标志
347     Append(path, vertex_1);                                                // 将当前顶点加入路径
348     for(Vertex tempVertex = FirstAdjoinVertex(graph, vertex_1); tempVertex != -1; tempVertex = NextAdjoinVertex(graph, vertex_1, tempVertex)) {
349         if(tempVertex == vertex_2) {                                       // 查找成功
350             Append(path, vertex_2);
351             return ;
352         }
353         if(!graph.visited(tempVertex))                                     // 递归调用
354             SimplePath(graph, tempVertex, vertex_2);
355     }
356     Delete(path, vertex_1);                                                // 删除路径上最后一个顶点
357 }
358
359 /**
360  * 非连通图的遍历
361  **/
362 void DepthFirstTraverse(Graph &graph, Vertex vertext)
363 {
364     for(vertext = 0; vertext < graph.vertextCount; ++vertext) {     // 只需把每个顶点作为起点进行深度优先遍历即可
365         graph.visited[vertext] = true;
366         for(int temp = FirstAdjoinVertex(graph, vertext); temp != -1; tmep = NextAdjoinVertex(graph, vertext, temp)) {
367             if(graph.visited[temp] == false)
368                 DepthFirstTraverse(graph, temp);
369         }
370     }
371 }
372
373 /**
374  * 拓扑排序
375  **/
376 void TopologicalSort(Graph &graph, int *topologicalSequence)
377 {
378     CircleQueue circleQueue;
379     InitQueue(circleQueue);
380     int *inDegrees = new int[graph.vertextCount];                        // 记录每个顶点的入度
381     for(int vertex = 0; vertex < graph.vertextCount; ++vertex)           // 初始化顶点入度
382         inDegrees[vertex] = 0;
383     for(int vertex = 0; vertex < graph.vertextCount; ++vertex) {         // 遍历图得到顶点输入边数
384         for(int tempVertex = FirstAdjoinVertex(graph, vertext); tempVertex != -1; tempVertex = NextAdjoinVertex(graph, vertex, tempVertex)) {
385             ++inDegrees[tempVertex];
386         }
387     }
388     for(int vertex = 0; vertex < graph.vertextCount; ++vertex)
389         if(inDegrees[vertex] == 0)
390             EnQueue(circleQueue, vertex);                                // 源点入源点队列
391     for(int index = 0; !IsEmpty(circleQueue); ++index) {                 // 开始拓扑排序
392         int outVertex;
393         DeQueue(circleQueue, &outVertex);
394         topologicalSequence[index] = outVertex;                          // 从源点队列中取元素如拓扑队列
395         for(int tempVertex = FirstAdjoinVertex(graph, outVertex); tempVertex != -1; tempVertex = NextAdjoinVertex(graph, outVertex, tempVertex)) {
396             --inDegrees[tempVertex];                                     // 源点的邻接顶点入度减1
397             if(inDegrees[tempVertex] == 0)
398                 EnQueue(circleQueue, tempVertex);                        // 若成为新源点,入源点队列
399         }
400     }
401     DetroyQueue(circleQueue);
402 }

Ok哒,哈哈~

Graph Theory Algorithms,布布扣,bubuko.com

时间: 2024-11-05 12:26:06

Graph Theory Algorithms的相关文章

Graph Theory: Representation and Algorithms

Summer Project - 2019Graph Theory: Representation and Algorithms1 IntroductionIn order to complete this project successfully, the student should be familiar with many basicnotions of graph theory. The questions below whose answers should be included

2017 UESTC Training for Graph Theory

2017 UESTC Training for Graph Theory A       思维 题意:给你一个有n个点和m条边的无向连通图,每条边都有一个权值w.我们定义,对于一条路径,它的Charm value为该路径上所有边的权值的最大值与最小值的差.询问从1到n的所有路径的Charm value的最小值. tags:有点思维定式了..一条路径里只要最大最小值,所以边可以重复走.这样我们只要把边从小到大枚举,把第 i 条边作为最小边,然后对于每个 i ,我们按顺序逐一加入比它大的边,直到点

Graph Theory

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 140    Accepted Submission(s): 74 Problem Description Little Q loves playing with different kinds of graphs very much. One day he thought about

ACM学习历程—NPU1045 2015年陕西省程序设计竞赛网络预赛(热身赛)C题 Graph Theory(递推 &amp;&amp; 组合数学 &amp;&amp; 大数)

Description In graph theory, a matching or independent edge set in a graph G = (V , E) is a set of edges ME such that no two edges in the matching M share a common vertex. The Nobel Prize in XiXiHaHa was awarded to Jerryxf team, amongst other things,

2018 Multi-University Training Contest 4 Problem L. Graph Theory Homework 【YY】

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6343 Problem L. Graph Theory Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 1536    Accepted Submission(s): 830 Problem Description Ther

图论介绍(Graph Theory)

1 图论概述 1.1 发展历史 第一阶段: 1736:欧拉发表首篇关于图论的文章,研究了哥尼斯堡七桥问题,被称为图论之父 1750:提出了拓扑学的第一个定理,多面体欧拉公式:V-E+F=2 第二阶段(19~20世纪): 1852: Francis Guthrie提出四色问题 1856: Thomas P. Kirkman & William R.Hamilton研究了哈密尔顿图 1878: Alfred Kempe给出给出四色定理证明 1890: 希伍德(Heawood)推翻原有四色定理证明 1

TCO14 2C L2: CliqueGraph,graph theory, clique

称号:http://community.topcoder.com/stat?c=problem_statement&pm=13251&rd=16017 參考:http://apps.topcoder.com/wiki/display/tc/TCO+2014+Round+2C 假设用先计算出每条边,用邻接矩阵来表示图,然后用BFS或 Floyd-Warshall算法来计算距离的话.时间复杂度是O(N^3),会超时.依据题名的提示知要利用clique graph的性质来做.基本思想是在BFS的

2017 Training for Graph Theory

A - 梦后楼台高锁,酒醒帘幕低垂(并查集 + 贪心) 给你一个有nn个点和mm条边的无向连通图,每条边都有一个权值ww.我们定义,对于一条路径,它的Charm valueCharm value为该路径上所有边的权值的最大值与最小值的差.询问从11到nn的所有路径的Charm valueCharm value的最小值. Input 第一行有两个整数n,m(1≤n≤200,n−1≤m≤1000)n,m(1≤n≤200,n−1≤m≤1000),表示该图有nn个点和mm条边.接下来mm行,每行三个整数

UESTC_方老师和农场 2015 UESTC Training for Graph Theory&lt;Problem L&gt;

L - 方老师和农场 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 方老师重新开了一家农场,农场一共有N个节点和M条双向边,但是有一个很大的问题就是有比如一个农场A到达农场B只有一条路径,问至少添加多少条边使得任意两个农场之间的路径多于一条. Input 多组数据,EOF结束. 第1行:N和M. 第2到第M+1行:每一行2个数Ui和Vi,表示Ui到