<C/C++算法> 图论基础算法小结(邻接矩阵实现)
来源:互联网 发布:国外刻录软件 编辑:程序博客网 时间:2024/05/16 06:20
以前用邻接表实现的图算法程序写得有点复杂,无法立刻看懂,重新用邻接矩阵写得简单点,某年某月能一看就回忆起该算法。
1,广度优先搜索算法
广度优先算法(Breadth-First-Search),又称作宽度优先搜索,或横向优先搜索,简称BFS,是一种图形搜索演算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点,如果发现目标,则演算终止。广度优先搜索的实现一般采用open-closed表。
#include<iostream> #include<windows.h> #include<vector> #include<queue> #include<set> using namespace std;#define vertex_nums 8bool BFS(vector<vector<int>> &graph , vector<int> &path,int start_vertex);//广度优先遍历要快速想到队列 int _tmain(int argc, _TCHAR* argv[]){system("color 0A");//初始化图vector<int> row(vertex_nums, -1);vector<vector<int>> graph(vertex_nums, row);for (int i = 0; i<vertex_nums; i++)graph[i][i] = 0;//自定义简单图的边及其权值graph[3][0]=1;graph[0][5]=1;graph[1][2]=3,graph[2][1]=3;graph[1][6]=1,graph[6][1]=1;graph[2][3]=5;graph[2][4]=1;graph[3][5]=3;graph[3][6]=1;graph[4][5]=1;graph[4][3]=3;graph[5][7]=1;graph[6][7]=3;graph[7][3]=3;vector<int> bfs_path(vertex_nums, -1);int s_v = 2, e_v = 7;BFS(graph, bfs_path, s_v);system("pause");return 0;}//广度优先检查图//时间复杂度O(v^2)//连接表的速度是O(v+e),对于稀疏图而言,邻接表更有优势! bool BFS(vector<vector<int>> &graph, vector<int> &bfs_path, int start_vertex){vector<int> visited(vertex_nums,0);visited[start_vertex] = 1;queue<int> que;que.push(start_vertex);//用于记录路径int idx = 0;bfs_path[idx++]=start_vertex;while (!que.empty()){int cur_ver = que.front();que.pop();//广度搜索当前节点的相邻节点for (int i = 0; i < vertex_nums; i++){if (graph[cur_ver][i] > 0 && visited[i] == 0){visited[i] = 1;bfs_path[idx++] = i;que.push(i);}}}return true;}
2,深度优先搜索算法
深度优先搜索算法(Depth-First-Search),是搜索算法的一种。是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。
#include<stdio.h> #include<string.h> #include<iostream> #include<windows.h> #include<vector> #include<queue> #include<set> using namespace std;#define vertex_nums 8bool DFS(vector<vector<int>> &graph, vector<int> &path, vector<int> &visited, int &idx, int start_vertex);int _tmain(int argc, _TCHAR* argv[]){system("color 0A");//初始化图vector<int> row(vertex_nums, -1);vector<vector<int>> graph(vertex_nums, row);for (int i = 0; i<vertex_nums; i++)graph[i][i] = 0;//自定义简单图的边及其权值graph[3][0]=1;graph[0][5]=1;graph[1][2]=3,graph[2][1]=3;graph[1][6]=1,graph[6][1]=1;graph[2][3]=5;graph[2][4]=1;graph[3][5]=3;graph[3][6]=1;graph[4][5]=1;graph[4][3]=3;graph[5][7]=1;graph[6][7]=3;graph[7][3]=3;vector<int> dfs_path(vertex_nums, -1);vector<int> visited(vertex_nums, 0);int s_v = 2, e_v = 7;int idx = 0;visited[s_v] = 1;DFS(graph, dfs_path, visited,idx, s_v);getchar();return 0;}//深度优先检查图//时间复杂度O(v^2)//连接表的速度是O(v+e),对于稀疏图而言,邻接表更有优势! bool DFS(vector<vector<int>> &graph, vector<int> &dfs_path, vector<int> &visited , int &idx, int start_vertex){dfs_path[idx++] = start_vertex;for (int i = 0; i < vertex_nums; i++){if (graph[start_vertex][i] > 0 && visited[i] == 0){visited[i] = 1;DFS(graph,dfs_path,visited,idx,i);}}return true;}
3,最短路径算法dijstra
始终记住最短路径算法的核心内容,每次迭代始终在更新shortpath中的最短路径值:
贪心的最短路径:shortpath[j]=min{shortpath[j],shortpath[i]+graph[i][j]}
shortpath[j]始终存放起点到j的当前最短路径,i为当前中心点
#include<stdio.h> #include<string.h> #include<iostream> #include<windows.h> #include<vector> #include<queue> #include<set> using namespace std;#define vertex_nums 8 int dijkstra(vector<vector<int>> &graph, int start_vertex, int end_vertex, vector<int> &path);int _tmain(int argc, _TCHAR* argv[]){system("color 0A");//初始化图 vector<int> row(vertex_nums, INT_MAX);vector<vector<int>> graph(vertex_nums, row);for (int i = 0; i<vertex_nums; i++)graph[i][i] = 0;//自定义简单图的边及其权值 graph[3][0] = 1;graph[0][5] = 1;graph[1][2] = 3, graph[2][1] = 3;graph[1][6] = 1, graph[6][1] = 1;graph[2][3] = 5;graph[2][4] = 1;graph[3][5] = 3;graph[3][6] = 1;graph[4][5] = 1;graph[4][3] = 3;graph[5][7] = 1;graph[6][7] = 3;graph[7][3] = 3;vector<int> path(vertex_nums, -1);int resukt = dijkstra(graph, 2, 7, path);for (int k = 7; path[k] != -1; k = path[k])cout << k << " ";cout << 2;getchar();return 0;}//最短路径:shortpath[j]=min{shortpath[j],shortpath[i]+graph[i][j]} //shortpath[j]始终存放起点到j的当前最短路径 int dijkstra(vector<vector<int>> &graph, int start_vertex, int end_vertex, vector<int> &path){vector<int> shortpath(vertex_nums, INT_MAX);//存储起点到各点的最短路径 vector<int> visited(vertex_nums, 0);//已访问过的顶点 for (int i = 0; i < vertex_nums; i++)//初始化当前原点到其他店的距离,如果不相连则为INT_MAX {if (graph[start_vertex][i] != INT_MAX)shortpath[i] = graph[start_vertex][i];}visited[start_vertex] = 1;//起点初始化为被访问,并以他为当前中心点开始找最短路径 int min_weight = INT_MAX;int u = -1;int nums = vertex_nums - 1;bool first = true;while (nums){min_weight = INT_MAX;u = -1;for (int i = 0; i < vertex_nums; i++){if (visited[i] == 0 && shortpath[i] < min_weight){u = i;min_weight = shortpath[i];}}if (first){path[u] = start_vertex;//更新记录前驱顶点,供最后回溯最短路径 first = false;}visited[u] = 1;//已经确定起点到u的最短路径 nums--;if (end_vertex == u)//如果u就是终点的话,就不用再找了! break;//以u为中间点寻找起点到顶点w的最短路径 for (int w = 0; w < vertex_nums; w++){if (visited[w] == 0 && graph[u][w] != INT_MAX && min_weight + graph[u][w] < shortpath[w]){shortpath[w] = min_weight + graph[u][w];//更新起点到w的最短路径值 path[w] = u;//更新记录前驱顶点,供最后回溯最短路径 }}}return shortpath[end_vertex];}
4,Prim算法
Prim算法是以图的顶点起始点,每次选取所有顶点上对应的权值最小的边进行构建,所以prim的时间开销和边无关,对于定点数为n时Prim的时间复杂度为 O(n^2),所以prim算法更适合求解边数很多的稠密图的MST。
具体步骤:将整个顶点集合分为两个子集U、V,U中存放已经在生成树中的顶点,V中存放未在生成树中的顶点。算法核心的每一步将从U、V中各选一顶点,并且边的权值w(u,v)是最小的,然后将该顶点v从V中移到U中,如此直到集合V为空,即完成。
#include<stdio.h> #include<string.h> #include<iostream> #include<windows.h> #include<vector> #include<queue> #include<set> using namespace std;#define vertex_nums 8 int Prim(vector<vector<int>> &graph);int _tmain(int argc, _TCHAR* argv[]){system("color 0A");//初始化图 vector<int> row(vertex_nums, INT_MAX);vector<vector<int>> graph(vertex_nums, row);for (int i = 0; i<vertex_nums; i++)graph[i][i] = 0;//自定义简单图的边及其权值 graph[3][0] = 1;graph[0][5] = 1;graph[1][2] = 3, graph[2][1] = 3;graph[1][6] = 1, graph[6][1] = 1;graph[2][3] = 5;graph[2][4] = 1;graph[3][5] = 3;graph[3][6] = 1;graph[4][5] = 1;graph[4][3] = 3;graph[5][7] = 1;graph[6][7] = 3;graph[7][3] = 3;cout<<"最小生成树的权值为: " << Prim(graph) << endl;getchar();return 0;}//lowcost[i]:表示以u为起点,i为终点的边的权值//closest[i]:表示对应lowcost[i]的起点//u为当前最短边的目的顶点(举例:2--->1,1就是目的顶点)int Prim(vector<vector<int>> &graph){int sum = 0;int u = 0;//起点vector<int> lowcost(vertex_nums, 0);vector<int> closest(vertex_nums,0);vector<bool> visited(vertex_nums,false);for (int i = 0; i < vertex_nums; i++)lowcost[i] = graph[u][i];//start_ver为起点visited[u] = true;for (int i = 1; i < vertex_nums; i++){int min = INT_MAX;u = -1;//寻找未被加入mst的最小权值边for (int k = 0; k < vertex_nums; k++){if ((lowcost[k] < min) && visited[k] == false){min = lowcost[k];u = k;}}if (u == -1)//不是连通图return -1;cout << closest[u] << "--->" << u << endl;//输出最小生成树的连接情况路径。sum += min;visited[u] = true;//更新当前节点u到其他节点的权值for (int k = 0; k < vertex_nums; k++){if ((graph[u][k] < lowcost[k]) && visited[k] == false){lowcost[k] = graph[u][k];closest[k] = u;}}}return sum;}
5,Kruskal算法
秒杀该算法:<C/C++数据结构>并查集及其常见面试题
该问题就是最小生成树问题:练习3,还是畅通工程
- 题目描述:
- 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
- 输入:
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
- 输出:
对每个测试用例,在1行里输出最小的公路总长度。
- 样例输入:
31 2 11 3 22 3 441 2 11 3 41 4 12 3 32 4 23 4 50
- 样例输出:
35
#include "vector" #include "string" #include "algorithm" #include <iostream> #include "stack" #include <cmath> #include <set> using namespace std; class Edge { public: int acity;//城市a int bcity;//城市b int cost; //建成a到b的路的花费 bool operator < (const Edge &q) const//注意返回值的类型,运算符重载。 { return cost<q.cost; } }; Edge edge[10000]; class UFSet { public: UFSet(int nsize) { size = nsize; parent = new int[size + 1]; }; ~UFSet() { delete[] parent; parent = NULL; }; // 初始化每个元素的祖先 void makeSet(int n); // 找到元素x的祖先元素 int findSet(int x); // 获取最小花费 int getMinCost(int m); private: int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x int size; }; void UFSet::makeSet(int n) //初始化 { //初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身 for (size_t i = 1; i <= n; i++) parent[i] = i; } int UFSet::findSet(int x) { //找到元素所在的集合,也就是找到自己的最高的祖先, //这也是判断两个元素是否在同一个集合中的主要依据。 if (parent[x] == x)//递归截止条件(最高祖先的祖先是其自身) return x; parent[x] = findSet(parent[x]);//递归,最终找到x的最高祖先,并且沿途找到所有的最高祖先 return parent[x]; } int UFSet::getMinCost(int m) { sort(edge, edge + m);//必须先对边排序(根据边的修建费用),这样才能贪心的形成最小花费 int sum = 0; for (int i = 0; i<m; i++) { int baseA = findSet(edge[i].acity);//找到城市a的祖先(要么是自身要么是城市b的编号) int baseB = findSet(edge[i].bcity); if (baseA != baseB) { parent[baseA] = baseB;//将城市a的祖先设置成b的祖先这个式子等价于parent[edge[i].acity] = edge[i].bcity sum += edge[i].cost; } } return sum; } int main() { int n = 0; while (cin >> n, n > 0) { int m = n*(n - 1) / 2; UFSet uset(100); uset.makeSet(n);//初始化每个城市的祖先为自身 for (int i = 0; i < m; i++) cin >> edge[i].acity >> edge[i].bcity >> edge[i].cost; int mincost = uset.getMinCost(m); cout << mincost << endl; } return 0; } /************************************************************** Problem: 1017 User: EbowTang Language: C++ Result: Accepted Time:30 ms Memory:1636 kb ****************************************************************/
- <C/C++算法> 图论基础算法小结(邻接矩阵实现)
- 基于邻接矩阵的Prim算法(C语言实现)
- Prim算法的C语言实现(邻接矩阵)
- 邻接矩阵实现图论的相关算法
- 图邻接矩阵存储 最小生成树 prim普里姆算法 C语言实现
- Prim算法(邻接矩阵无相图)求最小生成树 C 实现 ~
- 算法导论C语言实现: 算法基础
- 图的邻接矩阵(C语言实现)
- 数据结构与算法(C语言版)__邻接矩阵
- C/C++:各种基本算法实现小结(四)—— 图及其遍历
- C 排序算法小结
- 排序算法小结(C++)
- 排序算法小结(C#)
- C/C++:各种基本算法实现小结(五)—— 排序算法
- C/C++:各种基本算法实现小结(六)—— 查找算法
- C/C++:各种基本算法实现小结(七)—— 常用算法
- 图的邻接矩阵c语言表示(无向网)---《数据结构》算法7.2
- 邻接矩阵实现prim算法
- 日经春秋 20150921
- java 监听器ServletContextListener,服务启动加载及定时器
- Android 深入理解Android中的自定义属性
- Views动画 和ViewPropertyAnimator
- Node.js 笔记(一) nodejs、npm、express安装
- <C/C++算法> 图论基础算法小结(邻接矩阵实现)
- Java中List<>的用法
- poipdfsolr学习相关网址
- JDBC相关机制与JDBC连接数据库步骤
- IOS工具篇
- 数据结构之树
- C++中头文件(.h)和源文件(.cpp)都应该写些什么
- Linux下的一些I/O统计工具
- 洛谷1220关路灯