深度优先DFS和广度优先BFS,破圈法,拓扑序列,prim,克鲁斯卡尔等生成算法(需要用到并查集)迪杰斯特拉算法和弗洛伊德的总结
2016-12-16 16:07
791 查看
1.有向图:比较好
2.无向图是变态的有向图,需要注意度和节点之类的比如MST,最小生成树利用破圈法生成,关联的度为1的无向图节点肯定不是回路(不知道对不。。),1.找到图中的一个圈。2.删除其中的权最大的边。3.重复上述操作,直到图中已无圈。
针对无向图,可以这样做:
1.用拓扑分类算法,找到图中的圈。具体就是依次找到图中度为1的顶点(可以保存在队列里),删除之(这里的删除是暂时的,下次遍历还要还原这些点),然后与其邻接的顶点的入度-1,这样往复操作,直到图中已不存在入度为1的顶点,即所有的顶点的度都》=2,那么剩下的边就都在环里了。当然,如果没剩下边,说明没有环,算法结束。
2.剩下的边就都是环中的边了,找一个权最大的删去即可。
深度优先DFS和广度优先BFS的区分并不是看遍历结果
而是策略上的区分
简单说,深度优先 就是从某个点出发,依次递归深度优先遍历其每个未被访问的邻接点
广度优先,是从某个点出发,依次遍历其每个未被访问的邻接点(并做记录),再对之前一步记录的每个邻接点,重复上述过程
节点可变
3.还有prim,克鲁斯卡尔等生成算法(需要用到并查集)
4.迪杰斯特拉算法和弗洛伊德注重过程,怎么一步步来的,挺重要的
5.还有关键路径
关键路径分析
如图,每个节点表示一个必须执行的动作以及完成动作所花费的时间。该图叫做动作节点图。图中的边代表优先关系,一条边(v,w)意味着动作v必须在动作w开始前完成。(这意味着这个图必然是无圈的)。
这个图可以模拟两类问题:
1. 整个方案最早什么时间完成?
2. 确定哪些动作时可以延迟的,延迟多长,而不致影响最少完成时间?
我们把动作节点图转化为事件节点图
1. 每个事件对应一个动作和所有相关的动作的完成;
2. 从事件节点图中的节点v可达到的事件可以在事件v完成后开始;
3. 在一个动作依赖于几个其他动作的情况下,可能需要插入哑边和哑节点(保证每个真实点只有一条入边)。
为了找出方案的最早完成时间,我们只要找出从第一个事件到最后一个事件的最长路径长度。
由于这是个无圈图,可以采纳最短路径算法计算图中所有节点的最早完成时间。
如果ECi是节点i的最早完成时间,则有
1. EC1 = 0;
2. ECw = max(ECv + c(v,w))
用以下法则计算每个节点最晚完成时间
1. LCn = ECn;//最后一个点的最晚完成时间和最早完成时间相同
2.LCv = min(LCw - c(v,w))
对于每个顶点,通过保存一个所有邻接且在先的顶点的表,这些值就可以以线性时间算出。借助顶点的拓扑顺序计算它们的最早完成时间,而最晚完成时间则通过倒转它们的拓扑顺序来计算。
拓扑排序-》有向图
2.无向图是变态的有向图,需要注意度和节点之类的比如MST,最小生成树利用破圈法生成,关联的度为1的无向图节点肯定不是回路(不知道对不。。),1.找到图中的一个圈。2.删除其中的权最大的边。3.重复上述操作,直到图中已无圈。
针对无向图,可以这样做:
1.用拓扑分类算法,找到图中的圈。具体就是依次找到图中度为1的顶点(可以保存在队列里),删除之(这里的删除是暂时的,下次遍历还要还原这些点),然后与其邻接的顶点的入度-1,这样往复操作,直到图中已不存在入度为1的顶点,即所有的顶点的度都》=2,那么剩下的边就都在环里了。当然,如果没剩下边,说明没有环,算法结束。
2.剩下的边就都是环中的边了,找一个权最大的删去即可。
3.再进行1操作,直到图中无圈,即所有的圈都已破掉,剩下的就是最小生成树了。
还有DFS和BFS:深度优先DFS和广度优先BFS的区分并不是看遍历结果
而是策略上的区分
简单说,深度优先 就是从某个点出发,依次递归深度优先遍历其每个未被访问的邻接点
广度优先,是从某个点出发,依次遍历其每个未被访问的邻接点(并做记录),再对之前一步记录的每个邻接点,重复上述过程
节点可变
3.还有prim,克鲁斯卡尔等生成算法(需要用到并查集)
4.迪杰斯特拉算法和弗洛伊德注重过程,怎么一步步来的,挺重要的
5.还有关键路径
关键路径分析
如图,每个节点表示一个必须执行的动作以及完成动作所花费的时间。该图叫做动作节点图。图中的边代表优先关系,一条边(v,w)意味着动作v必须在动作w开始前完成。(这意味着这个图必然是无圈的)。
这个图可以模拟两类问题:
1. 整个方案最早什么时间完成?
2. 确定哪些动作时可以延迟的,延迟多长,而不致影响最少完成时间?
我们把动作节点图转化为事件节点图
1. 每个事件对应一个动作和所有相关的动作的完成;
2. 从事件节点图中的节点v可达到的事件可以在事件v完成后开始;
3. 在一个动作依赖于几个其他动作的情况下,可能需要插入哑边和哑节点(保证每个真实点只有一条入边)。
为了找出方案的最早完成时间,我们只要找出从第一个事件到最后一个事件的最长路径长度。
由于这是个无圈图,可以采纳最短路径算法计算图中所有节点的最早完成时间。
如果ECi是节点i的最早完成时间,则有
1. EC1 = 0;
2. ECw = max(ECv + c(v,w))
用以下法则计算每个节点最晚完成时间
1. LCn = ECn;//最后一个点的最晚完成时间和最早完成时间相同
2.LCv = min(LCw - c(v,w))
对于每个顶点,通过保存一个所有邻接且在先的顶点的表,这些值就可以以线性时间算出。借助顶点的拓扑顺序计算它们的最早完成时间,而最晚完成时间则通过倒转它们的拓扑顺序来计算。
拓扑排序-》有向图
#include <iostream> #include<stack> #include<queue> #include "MinHeap.h" #include "MaxHeap.h" using namespace std; class UFsets{ private: int n; int *root; int *next; int *length; public: UFsets(int size) { n=size; root =new int ; next =new int ; length=new int ; for(int i=0;i<n;i++) { root[i]=next[i]=i; length[i]=1; } } int Find(int v) { return root[v]; } void Union(int v,int u) { if(root[v]==root[u]) return; else if(length[root[v]]<length[root[u]]) { int rt=root[v]; length[root[u]]+=length[rt]; root[rt]=root[u]; for(int j=next[rt];j!=rt;j=next[j]) { root[j]=root[u]; } std::swap(next[rt],next[root[u]]); } else { int rt=root[u]; length[root[v]]+=length[rt]; root[rt]=root[v]; for(int j=next[rt];j!=rt;j=next[j]) { root[j]=root[v]; } std::swap(next[rt],next[root[u]]); } } }; template<class T> class Edge { public: int start,end; T weight; Edge(int st,int ed,int w){start=st;end=ed;weight=w;}; Edge(){weight=0;end=-1;}; bool operator >(Edge one) { return weight>one.weight; }; bool operator <(Edge one) { return weight<one.weight; }; }; template<class T> class AdjGraph { public: int vertexNum; int edgeNum; int *Mark; int **marix; int getVertexNum(){return vertexNum;}; int getEdgesNum(){return edgeNum;}; bool IsEdge(Edge<T> one) { if(one.weight>0&&one.end>=0) { return true; } else { return false; } } int startVertex(Edge<T>one) { return one.start; } int endVertex(Edge<T>one) { return one.end; } T Weight(Edge<T> one) { return one.weight; } AdjGraph(int verticeNum) { vertexNum=verticeNum; edgeNum=0; vertexNum=verticeNum; Mark= new int[vertexNum]; for(int i=0;i<vertexNum;i++) { Mark[i]=0; } int i,j; marix=new int*[vertexNum]; for(i=0;i<vertexNum;i++) marix[i]=new int[vertexNum]; for(i=0;i<vertexNum;i++) for(j=0;j<vertexNum;j++) marix[i][j]=9999; } ~AdjGraph() { for(int i=0;i<vertexNum;i++) delete []marix[i]; delete []marix; } Edge<T> FirstEdge(int one) { Edge<T> tempEdge; tempEdge.start=one; for(int i=0;i<vertexNum;i++) { if(marix[one][i]!=0) { tempEdge.end=i; tempEdge.weight=marix[one][i]; break; } } return tempEdge; } Edge<T> NextEdge(Edge<T> one) { Edge<T> tempEdge; tempEdge.end=-1; tempEdge.start=one.start; for(int i=one.end+1;i<vertexNum;i++) { if(marix[one.start][i]!=0) { tempEdge.end=i; tempEdge.weight=marix[one.start][i]; break; } } return tempEdge; } void setEdge(int start,int end,T weight) { if(marix[start][end]==9999) { edgeNum++; } marix[start][end]=weight; } void delEdge(int start,int end) { if(marix[start][end]!=0) { edgeNum--; } marix[start][end]=0; } void visit(int v) { cout<<v+1<<endl; } void DFS(int i) { Mark[i]=1; visit(i); for(int j=0;j<vertexNum;j++) { if(marix[i][j]!=9999&&(Mark[j]==0)) { DFS(j); } } } void DFSTraverse() { for(int i=0;i<vertexNum;i++) { Mark[i]=0; } for(int i=0;i<vertexNum;i++) { if(Mark[i]==0) DFS(i); } } void DFSNoReverse() { int i; using std::stack; stack<int >s; for(i=0;i<vertexNum;i++) { Mark[i]=0; } cout<<1<<endl; for(int i = 0; i <vertexNum; i++) { if(marix[i][0]!=9999&& !Mark[i] )/*先存储到栈不访问*/ { Mark[i] = 1; s.push(i); } } while(!s.empty()) { int s_top = s.top(); Mark[s_top] = 1; visit(s_top); s.pop(); for(int i = 1; i <= vertexNum-1; i++) { if(marix[i][s_top]!=9999 && !Mark[i] )/*先存储到栈不访问*/ { Mark[i] = 1; s.push(i); } } } } void Dijkstra(T mar[6][6],int n,int v,int flag[],int path[]) { int *dist=new int ; for(int i=0;i<n;i++) { dist[i]=mar[v][i]; path[i]=v; flag[i]=0; } flag[v]=1; for(int i=0;i<n-1;i++) { int min=9999; int k=0; for(int i=0;i<n;i++) { if(!flag[i]) { if(dist[i]<min) { min=dist[i]; k=i; } } } cout<<k<<" "<<endl; flag[k]=1;/*添加到集合*/ for(int j=0;j<n;j++) { if(!flag[j]) { if(dist[j]>(dist[k]+mar[k][j])) { path[j]=k; dist[j]=dist[k]+mar[k][j]; } } } } cout<<"Path---"; for(int i=0;i<n;i++) { cout<<path[i]<<" "; } cout<<endl; } void BFSTraverse() { int v; for(v=0;v<vertexNum;v++) Mark[v]=0; int start=0; visit(start); Mark[start]=1; using std::queue; queue<T >q; q.push(start); while(!q.empty()) { T temp=q.front(); q.pop(); if(!Mark[temp]) { visit(temp); Mark[temp]=1; } for(int i=0;i<vertexNum;i++) { if(marix[temp][i]!=9999&&(!Mark[i])) q.push(i); } } } AdjGraph Prim() { int lowcost[vertexNum],vset[vertexNum],v,lowcostr[vertexNum]; int i,j,k,min,r; int sum=0; AdjGraph a(vertexNum); for(i=0;i<vertexNum;i++) { lowcost[i]=marix[0][i];/*lowcost[] represents the minimal weight (Tree->node minweight)*/ vset[i]=0;/*wheater exist in the tree*/ lowcostr[i]=0; } vset[0]=1;/*insert to the tree*/ for(i=0;i<vertexNum-1;i++)/*insert n-1 times*/ { min=99999; for(j=0;j<vertexNum;j++)//寻找未访问的最小边的节点 { if(vset[j]==0&&lowcost[j]<min) { r=lowcostr[j]; min=lowcost[j]; k=j; } } vset[k]=1; a.setEdge(r,k,min); a.setEdge(k,r,min); sum+=min; v=k; for(j=0;j<vertexNum;j++)//更新最小边 { if(vset[j]==0&&marix[v][j]<lowcost[j]) { lowcostr[j]=v; lowcost[j]=marix[v][j]; } } } cout<<"the sum of weight is "<<sum<<endl; return a; } AdjGraph Kruskal() { int n=vertexNum; UFsets set(n); AdjGraph<T> b(n); int sum=0; MinHeap<Edge<T> > h(edgeNum/2); Edge<T> edge; for(int i=0;i<vertexNum;i++) { for(int j=0;j<vertexNum;j++) { if((j>i)&&(marix[i][j]!=9999)) { Edge<T>a(i,j,marix[i][j]); h.insert(a); } } } int edgenums=0; while(edgenums<n-1) { if(!h.empty()) { h.deleteTop(edge);//找最小边 int v=edge.start; int u=edge.end; if(set.Find(v)!=set.Find(u))//合并最小 { set.Union(v,u);//并查集 b.setEdge(edge.start,edge.end,edge.weight); b.setEdge(edge.end,edge.start,edge.weight); edgenums++; } } } return b; } void Floyd(int adj[3][3],int path[3][3]) { int i,j,k,v; for(i=0;i<vertexNum;i++) { for(j=0;j<vertexNum;j++) { if(i==j) { adj[i][j]=0; path[i][j]=i+1; } else { adj[i][j]=9999; path[i][j]=-1; } } } for(v=0;v<vertexNum;v++)//初始化 { for(j=0;j<vertexNum;j++) { if(marix[v][j]!=9999) adj[v][j]=marix[v][j]; else adj[v][j]=0; path[v][j]=v+1; } } for(v=0;v<vertexNum;v++) {for(i=0;i<vertexNum;i++) { for(j=0;j<vertexNum;j++) {if(adj[i][j]>(adj[i][v]+adj[v][j])) { adj[i][j]=adj[i][v]+adj[v][j]; path[i][j]=v+1; } } } } for(int i=0;i<vertexNum;i++) { for(int j=0;j<vertexNum;j++) cout<<path[i][j]<<" "; cout<<endl; } } void FindcycleByTopogySort(int ** marix,int *SortArray) { int *indegree=new int[vertexNum]; int v; for(v=0;v<vertexNum;v++)//init { indegree[v]=0; Mark[v]=0; } for(v=0;v<vertexNum;v++)//统计入度个数 { for(int j=0;j<vertexNum;j++) { if(marix[v][j]==1) { indegree[j]++; } } } for(int i=0;i<vertexNum;i++) { for(v=0;v<vertexNum;v++) { if(indegree[v]==0&&Mark[v]==0) { break; } } if(v==vertexNum) { for(int i=0;i<vertexNum;i++) { if(!Mark[i]) { DFS(i); break; } } } else { Mark[v]=1; SortArray[i]=v; for(int j=0;j<vertexNum;j++) { if(marix[v][j]==1) { indegree[j]--; } } } } } void MSTByTopogySort() { AdjGraph<int> adj(vertexNum); int *indegree=new int[vertexNum]; int v; int count=edgeNum/2; int flag=1; int flag2=1; while(count>vertexNum-1) { for(v=0;v<vertexNum;v++)//init { indegree[v]=0; Mark[v]=0; } for(v=0;v<vertexNum;v++)//统计入度个数 { for(int j=0;j<vertexNum;j++) { adj.marix[v][j]==marix[v][j]; if(marix[v][j]!=9999) { indegree[j]++; } } } for(int i=0;i<vertexNum;i++) { cout<<indegree[i]<<endl; } flag=1; for(int i=0;i<vertexNum&&flag;i++) { for(v=0;v<vertexNum;v++) { if(((indegree[v]==1))&&Mark[v]==0) { break; } } if(v==vertexNum) { int flag1=1; for(int i=0;i<vertexNum;i++) { if(!Mark[i]) { Mark[i]=1; int b=i; MaxHeap<Edge<T> > e(edgeNum/2); for(int a=i;a<vertexNum&&flag1;a++) { for(int j = i; j <vertexNum&&flag1; j++) { if(indegree[j]==1) { flag1=0; } } } if(flag1) { for(int a=b;a<vertexNum&&flag1;a++) { for(int j = b; j <vertexNum&&flag1; j++) { Edge<T>ee(a,j,marix[a][j]); if(j>a&&(marix[a][j]!=9999)) { e.insert(ee); } } } } Edge<T>ee; e.deleteTop(ee); adj.marix[ee.start][ee.end]=9999; adj.marix[ee.end][ee.start]=9999; cout<<"bian"<<ee.start+1<<" "<<ee.end+1<<" "<<ee.weight<<endl; marix[ee.start][ee.end]=9999; marix[ee.end][ee.start]=9999; indegree[ee.start]--; indegree[ee.end]--; count--; flag=0; break; } } } else { Mark[v]=1; for(int j=0;j<vertexNum;j++) { if(marix[v][j]!=9999) { indegree[j]--; indegree[v]--; } } } } } DFSNoReverse(); } }; int main() { /* AdjGraph<int >d(8); d.setEdge(0,1,1); d.setEdge(0,2,1); d.setEdge(1,3,1); d.setEdge(1,4,1); d.setEdge(3,7,1); d.setEdge(4,7,1); d.setEdge(2,5,1); d.setEdge(2,6,1); d.setEdge(5,6,1); d.setEdge(6,5,1); d.setEdge(6,2,1); d.setEdge(5,2,1); d.setEdge(7,4,1); d.setEdge(7,3,1); d.setEdge(4,1,1); d.setEdge(3,1,1); d.setEdge(2,0,1); d.setEdge(1,0,1); /* for(int i=0;i<a.getVertexNum();i++) { for(int j=0;j<a.getVertexNum();j++) cout<<a.marix[i][j]; cout<<endl; } cout<<"DFS-"<<endl; d.DFSNoReverse(); cout<<"BFS-"<<endl; d.BFSTraverse(); cout<<"DFS-(digui)"<<endl; d.DFSTraverse();*/ AdjGraph<int> a(6); a.setEdge(0,1,6); a.setEdge(0,3,5); a.setEdge(0,2,1); a.setEdge(1,2,5); a.setEdge(1,4,3); a.setEdge(2,4,6); a.setEdge(2,5,4); a.setEdge(2,3,5); a.setEdge(3,5,2); a.setEdge(4,5,6); a.setEdge(1,0,6); a.setEdge(3,0,5); a.setEdge(2,0,1); a.setEdge(2,1,5); a.setEdge(4,1,3); a.setEdge(4,2,6); a.setEdge(5,2,4); a.setEdge(3,2,5); a.setEdge(5,3,2); a.setEdge(5,4,6); AdjGraph<int> b(6); b=a.Kruskal(); cout<<"------------------------------Kruskal--------------"<<endl; for(int i=0;i<b.getVertexNum();i++) { cout<<i+1<<" "; for(int j=0;j<b.getVertexNum();j++) cout<<b.marix[i][j]<<" "; cout<<endl; } cout<<"------------------------------Prim--------------"<<endl; AdjGraph<int> c(6); c=a.Prim(); for(int i=0;i<c.getVertexNum();i++) { cout<<i+1<<" "; for(int j=0;j<c.getVertexNum();j++) cout<<c.marix[i][j]<<" "; cout<<endl; } /*AdjGraph<int> c(6); c.setEdge(0,2,10); c.setEdge(1,2,5); c.setEdge(0,4,30); c.setEdge(0,5,100); c.setEdge(2,3,50); c.setEdge(3,5,10); c.setEdge(4,3,20); c.setEdge(4,5,60); int flag[6]; int path[6]; c.Dijkstra(c.marix,c.vertexNum,0,flag,path); return 0;*/ /* AdjGraph<int> e(3); e.setEdge(0,2,5); e.setEdge(2,0,2); e.setEdge(2,1,13); e.setEdge(1,2,6); e.setEdge(0,1,10); e.setEdge(1,0,9); int path[3][3]; int adj[3][3]; e.Floyd(adj,path);*/ AdjGraph<int> f(4); f.setEdge(0,1,1); f.setEdge(0,2,1); f.setEdge(2,1,1); f.setEdge(3,2,1); f.setEdge(1,3,1); int dd[5]; f.FindcycleByTopogySort(f.marix,dd); /*AdjGraph<int> a(6); a.setEdge(0,1,6); a.setEdge(0,3,5); a.setEdge(0,2,1); a.setEdge(1,2,5); a.setEdge(1,4,3); a.setEdge(2,4,6); a.setEdge(2,5,4); a.setEdge(2,3,5); a.setEdge(3,5,2); a.setEdge(4,5,6); a.setEdge(1,0,6); a.setEdge(3,0,5); a.setEdge(2,0,1); a.setEdge(2,1,5); a.setEdge(4,1,3); a.setEdge(4,2,6); a.setEdge(5,2,4); a.setEdge(3,2,5); a.setEdge(5,3,2); a.setEdge(5,4,6); a.MSTByTopogySort();*/ }
相关文章推荐
- 数据结构和算法总结(一):广度优先搜索BFS和深度优先搜索DFS
- 算法学习(2):BFS/DFS-广度优先/深度优先
- 二叉树深度优先(DFS)和广度优先(BFS)算法的非递归实现
- 深度优先搜索DFS和广度优先搜索BFS的总结
- 数据结构——图常用算法实现(DFS,BFS,最小生成树,最短路径,拓扑序列)
- 邻接矩阵存储的无向图深度优先(DFS)广度优先(BFS)遍历
- 图的BFS遍历和DFS遍历(广度优先和深度优先)
- 图论中最小生成树算法-Prim(普里姆)算法、kruskal(克鲁斯卡尔避圈法)算法、破圈算法
- Java数据结构----图--深度优先遍历BFS和广度优先遍历DFS
- 最小生成树算法汇总 (普里姆 && 克鲁斯卡尔与并查集结合)
- 【算法——02】图的遍历——BFS广度优先搜索、DFS深度优先搜索
- python遍历文件夹——深度优先(DFS)/广度优先(BFS)
- 树的存储结构和图的存储结构以及图的深度优先DFS搜索和BFS广度优先搜索
- 最小生成树之克鲁斯卡尔(Kruskal)算法、普里姆(prim)算法
- 邻接矩阵深度优先和广度优先遍历(DFS和BFS)
- 图的 储存 深度优先(DFS)广度优先(BFS)遍历
- 22.基于 邻接表 表示的 深度优先搜索dfs 和 广度优先搜索bfs
- 邻接表c源码(构造邻接矩阵,深度优先遍历,广度优先遍历,最小生成树prim,kruskal算法)
- 最小生成树算法(prim 克鲁斯卡尔(并差集))
- 深度优先DFS和广度优先BFS的非递归实现