图基础总结(算法导论)

1.图的基本算法

a.广、深度遍历

#include
#include
#include
#include
using namespace std;
//邻接矩阵存储
bool random(int s,int e)
{
	return s+rand()%(e-s);
}
void breadthFirstSearch(const vector< vector > &gmap,vector &isvis,int sp)
{
	if(isvis[sp])
	{
		return;
	}		
	queue q;
	q.push(sp);
	isvis[sp]=true;
	while(!q.empty())
	{
		sp=q.front();
		q.pop();
		cout< > &gmap,vector &isvis,int sp)
{
	if(isvis[sp])
	{
		return;
	}
	cout<>num;
	vector< vector > gmap;
	vector isvis1;
	for(int i=0;i temp;
		for(int j=0;j=6 
		gmap[5][i]=false;
		gmap[i][3]=false;
		gmap[3][i]=false;
		gmap[5][3]=true;
		gmap[3][5]=true;
	}
	for(int i=0;i isvis;
	cout<<"广度"<:";
		breadthFirstSearch(gmap,isvis,i);
		cout<:";
		depthFirstSearch(gmap,isvis,i);
		cout<
b.拓扑序列

减治法,visit一个顶点,减去该顶点和他所有的边。输出入度为0的节点,入度为0的节点没有前驱节点,所以肯定得先输出

#include
#include
#include
using namespace std;
const int num=5;
int main()
{
	vector< vector > gmap;
	vector isvis;
	vector f;
	for(int i=0;i temp;
		for(int j=0;j

深度优先遍历来做拓扑序列

深度遍历一次,并记下该端变为死端的顺序,这个顺序反过来就是拓扑序列


【1【2【3【5,5】3】【4,4】2】1】,各顶点变成死端的顺序为(5,3,4,2,1),所以拓扑序列为(1,2,4,3,5)

遍历边1->2,1的出度减1。出度为0的端点,就是死端,死端因为没有出边,所以没有后续节点,所以一定是最后输出的。

#include
#include
#include
using namespace std;
const int num=5;
void DFS(vector< vector > &g,vector &isvis,int sp,stack &s)
{
	if(isvis[sp])
	{
		return;
	}
	isvis[sp]=true;
	for(int i=0;i > g;
	vector isvis;
	stack s;
	
	for(int i=0;i temp;
		for(int j=0;j
c.强连通分量

强连通定义:任意两个顶点之间,都有互通路径(不是边!),v有路径到w,w也有路径到v。

Kosaraju_Algorithm:(不会证明

•  step1:对原图G进行深度优先遍历,记录每个节点的离开时间。(得到G图的伪拓扑序列)

•  step2:选择具有最晚离开时间的顶点,对反图GT进行遍历,删除能够遍历到的顶点,这些顶点构成一个强连通分量。

•  step3:如果还有顶点没有删除,继续step2,否则算法结束。

图基础总结(算法导论)_第1张图片

#include
#include
#include
using namespace std;

void DFS(const vector< vector > &g,vector &isvis,int sp,stack &s)
{
	if(isvis[sp])
	{
		return;
	}
	isvis[sp]=true;
	for(int i=0;i > &g,vector &isvis,int sp)
{
	if(isvis[sp])
	{
		return;
	}
	isvis[sp]=true;
	cout< >g;
	vector isvis;
	stack s;
	//输入图 
	for(int i=0;i temp1;
		for(int j=0;j:";
		DFS2(g,isvis,sp);
		cout<
2.最小生成树

a.kruskal(并查集来做)

#include
#include
using namespace std;
#define Maxv 100+5
struct Node
{
	int v2;
	int v1;
	int len;
};
struct cmp
{
	bool operator()(Node a,Node b)
	{
		return a.len>b.len;
	}
};

int dis[Maxv][Maxv];//dis[i][j]等于0时表示不连通 ,不等于1时表示边权值 
int fa[Maxv];//father,并查集 

int Getfa(int i)//查找根节点的函数 
{
	if(fa[i]!=i)//如果不是根节点 
		fa[i]=Getfa(fa[i]);//找根节点 
	return fa[i];//返回节点i所在集合的根节点	
} 
int main()
{
   	 int sum;//最小生成树代价
     priority_queue,cmp> Q;//声明小顶堆,返回最小数 
 
 	 int vn;//图中的顶点个数 
	 int i;
	 int j;	  
 	 cin>>vn;
	//输入图
	 for(i=1;i<=vn;i++)
	 {
		for(j=1;j<=vn;j++)
		{
			cin>>dis[i][j];	
   		}
	 } 
	 for(i=1;i<=vn;i++)
	 {
		fa[i]=i;//并查集,father,一开始有vn个节点,就有vn个集合 
	 }
	 while(!Q.empty())
	 {
		Q.pop();
	 }
	 //把每条边压入堆中
	 for(i=1;i
b.prim
/************************************************************************************************************************** 
Prim最小生成树:1.从顶点0开始搜素最小权边
                2.搜索到最短边之后,将另一个顶点u加入点集,将最短边值加入ret(总边权值)
		3.判断从顶点u出发的边map[u][j](j为未加入点集的点),是否小于原先点集的点到点j的距离,如果是就替换掉
		4.prim是遍历顶点,所以邻接矩阵比较合适
***************************************************************************************************************************/ 

#define MaxN 101

int n,ret;
int map[MaxN][MaxN];

void prim()
{
	int closet[MaxN];//该点是否加入点集,1表示加入,0表示不加入 
	int dist[MaxN];//点集到各个离散点的距离
	int i,j;
	for(i=0;i0)//点j未加入点集,点j与顶点之间的有边,且边权小于min
			{
				u=j;
				min=dist[j];
			}
		}
		closet[u]=1;//顶点u加入点集
		ret=ret+min;//总边权值
		for(j=1;j
 
  

3.单源最短路径

a.bellman-ford

支持负边权,但不支持负权回路

负权回路:

在一个图里每条边都有一个权值(有正有负)如果存在一个环(从某个点出发又回到自己的路径),而且这个环上所有权值之和是负数,那这就是一个负权环,也叫负权回路存在负权回路的图是不能求两点间最短路的, 因为只要在负权回路上不断兜圈子,所得的最短路长度可以任意小。

1.数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为无穷大, Distant[s]为0;

2.以下操作循环执行至多n-1次,n为顶点数:

对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;

3.为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。

#include
#include
using namespace std;
const int max_int=200;//最大值199,200及以上视为无穷大
struct Eage
{
	int u;
	int v;
	int cost;
};
bool bellmanFord(int num,vector &d,const vector e)
{
	int nume=e.size();
	//松弛 
	for(int i=0;id[e[j].u]+d[e[j].cost])
			{
				d[e[j].v]=d[e[j].u]+d[e[j].cost];
			}
		}
	}
	//检测负权回路 
	for(int i=0;id[e[i].u]+d[e[i].cost])
		{
			return false;
		}
	}
	return true;
} 
void initDE(vector &e,vector &d,int nodenum,int eagenum,int sp)
{
	for(int i=0;i>tempe.u>>tempe.v>>tempe.cost;
		e.push_back(tempe);
		if(tempe.u==sp)
		{
			d[tempe.v]=tempe.cost;
		}
	}
}
int main()
{
	int nodenum;
	int eagenum;
	int sp;
	vector d;
	vector e;
	cin>>nodenum>>eagenum>>sp;
	initDE(e,d,nodenum,eagenum,sp);
	if(bellmanFord(nodenum,d,e))
	{
		for(int i=0;i

b.Dijkstra

迪杰斯特拉不支持负边权

图基础总结(算法导论)_第2张图片

#include
#include
#include
using namespace std;
int getMin(int dist[5],bool vt[5])
{
	int min=INT_MAX;
	int mark;
	for(int i=0;i<5;i++)
	{
		if(!vt[i]&&min>dist[i]&&dist[i]>0)
		{
			min=dist[i];
			mark=i;	
		}
	}
	return mark;
}
void dijkstra(int dis[5][5],bool vt[5],int dist[5],int v)
{
	int mark;
	vt[v]=true;
	for(int i=0;i<5;i++)
	{
		dist[i]=dis[v][i];
		cout<0&&dist[mark]+dis[mark][i]0)||(dist[i]<0&&dis[mark][i]>0&&dis[mark][i]>0)))
			{
				dist[i]=dist[mark]+dis[mark][i];
			}
			cout<>v;
	dijkstra(dis,vt,dist,v);
	cout<<"the distance is:"<

c.有向无环图最短路径

1.求有向无环图的拓扑序列

2.松弛

图基础总结(算法导论)_第3张图片

#include
#include
#include
using namespace std;
const int num=6;
const int max_int=999;
void DFS(const vector< vector > &g,vector &isvis,int sp,stack &s)
{
	if(isvis[sp])
	{
		return;
	}
	isvis[sp]=true;
	int num=g.size();
	for(int i=0;i=0&&!isvis[i])
		{
			DFS(g,isvis,i,s);
		}
	}
	s.push(sp);
}
void initGID(vector< vector > &g,vector &isvis,vector &d)
{
	for(int i=0;i tempg;
		for(int j=0;j > &g,vector &d,stack &s,vector &path)
{
	while(!s.empty())
	{
		path.push_back(s.top());
		s.pop();
	}
	//松弛 
	for(int i=1;i=0;j--)
		{
			if(d[path[i]]>d[path[j]]+g[path[j]][path[i]])
			{
				d[path[i]]=d[path[j]]+g[path[j]][path[i]];
			}
		}
	}
}
int main()
{
	vector< vector > g;
	stack s;
	vector isvis;
	vector d;
	vector path;
	initGID(g,isvis,d);
	//获取有向无环图的拓扑序列,如果点u到点v有路径,那么在拓扑序列中,点u一定先于点v 
	DFS(g,isvis,0,s);
	dagSP(g,d,s,path);
	for(int i=0;i

4.每对顶点间的最短路径

a.

可以用动规来做,迪杰斯特拉可以做,表明该问题存在最优子结构,应该可以用动规来做,for【i,for【j,for【组长,for【小于组长1个规模的阵所有最优解】】】】,大约是O(n^4);也可以用for【迪杰斯特拉】来做大约是;也可以for【贝尔曼弗洛德】来做;

b.Floyd-Warshall(O(n^3)

#include
#include
using namespace std;
int num;
const int max_int=999;
void initGD(vector< vector > &d)
{
	for(int j=0;j tempd;
		for(int k=0;k>temp;
			d[i][j]=temp;
		}
	}
	cout<<"***************"< > &d)
{
	for(int k=0;kd[i][k]+d[k][j]&&d[i][k]!=max_int&&d[k][j]!=max_int)
				{
					d[i][j]=d[i][k]+d[k][j];
				}
			}
		}
	}
}
int main()
{
	vector< vector > d;
	cin>>num;
	initGD(d);
	floydWarshall(d);
	for(int i=0;i
c.稀疏图上的johnson算法

暂待

5.最大流

回忆时,理解不了,就去看视频,纸质一张图涵盖信息太大,理解起来会有困难的

图基础总结(算法导论)_第4张图片





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