图论基础算法小结(邻接矩阵实现)

以前用邻接表实现的图算法程序写得有点复杂,无法立刻看懂,重新用邻接矩阵写得简单点,某年某月能一看就回忆起该算法。

1,广度优先搜索算法

广度优先算法(Breadth-First-Search),又称作宽度优先搜索,或横向优先搜索,简称BFS,是一种图形搜索演算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点,如果发现目标,则演算终止。广度优先搜索的实现一般采用open-closed表。

#include  
#include  
#include  
#include  
#include  

using namespace std;

#define vertex_nums 8

bool BFS(vector> &graph , vector &path,int start_vertex);//广度优先遍历要快速想到队列  

int _tmain(int argc, _TCHAR* argv[])
{
	system("color 0A");
	//初始化图
	vector row(vertex_nums, -1);
	vector> graph(vertex_nums, row);
	for (int i = 0; i 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> &graph, vector &bfs_path, int start_vertex)
{
	vector visited(vertex_nums,0);
	visited[start_vertex] = 1;
	queue 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  
#include  
#include  
#include  
#include  
#include  
#include  

using namespace std;

#define vertex_nums 8

bool DFS(vector> &graph, vector &path, vector &visited, int &idx, int start_vertex);

int _tmain(int argc, _TCHAR* argv[])
{
	system("color 0A");
	//初始化图
	vector row(vertex_nums, -1);
	vector> graph(vertex_nums, row);
	for (int i = 0; i dfs_path(vertex_nums, -1);
	vector 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> &graph, vector &dfs_path, vector &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    
#include    
#include    
#include    
#include    
#include    
#include    

using namespace std;

#define vertex_nums 8  

int dijkstra(vector>  &graph, int start_vertex, int end_vertex, vector &path);

int _tmain(int argc, _TCHAR* argv[])
{
	system("color 0A");

	//初始化图  
	vector row(vertex_nums, INT_MAX);
	vector> graph(vertex_nums, row);
	for (int i = 0; i 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>  &graph, int start_vertex, int end_vertex, vector &path)
{
	vector shortpath(vertex_nums, INT_MAX);//存储起点到各点的最短路径  
	vector 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    
#include    
#include    
#include    
#include    
#include    
#include    

using namespace std;

#define vertex_nums 8  

int Prim(vector>   &graph);

int _tmain(int argc, _TCHAR* argv[])
{
	system("color 0A");

	//初始化图  
	vector row(vertex_nums, INT_MAX);
	vector> graph(vertex_nums, row);
	for (int i = 0; i1,1就是目的顶点)
int Prim(vector>   &graph)
{
	int sum = 0;
	int u = 0;//起点
	vector lowcost(vertex_nums, 0);
	vector closest(vertex_nums,0);
	vector 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算法

秒杀该算法:并查集及其常见面试题


该问题就是最小生成树问题:练习3,还是畅通工程

题目描述:
    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
输入:

    测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
    当N为0时,输入结束,该用例不被处理。

输出:

    对每个测试用例,在1行里输出最小的公路总长度。

样例输入:
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
样例输出:
3
5

#include "vector"  
#include "string"  
#include "algorithm"  
#include   
#include "stack"  
#include   
#include   
  
using namespace std;  
  
  
  
class Edge  
{  
public:  
    int acity;//城市a    
    int bcity;//城市b    
    int cost;  //建成a到b的路的花费    
    bool operator < (const Edge &q) const//注意返回值的类型,运算符重载。    
    {  
        return cost> 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  
****************************************************************/



你可能感兴趣的:(数学与算法,数据结构与算法)