1.图的基本算法
a.广、深度遍历
b.拓扑序列#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< 减治法,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的端点,就是死端,死端因为没有出边,所以没有后续节点,所以一定是最后输出的。
c.强连通分量#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
2.最小生成树强连通定义:任意两个顶点之间,都有互通路径(不是边!),v有路径到w,w也有路径到v。
Kosaraju_Algorithm:(不会证明)
• step1:对原图G进行深度优先遍历,记录每个节点的离开时间。(得到G图的伪拓扑序列)
• step2:选择具有最晚离开时间的顶点,对反图GT进行遍历,删除能够遍历到的顶点,这些顶点构成一个强连通分量。
• step3:如果还有顶点没有删除,继续step2,否则算法结束。
#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<
a.kruskal(并查集来做)
b.prim#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
/************************************************************************************************************************** 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;i d[e[j].u]+d[e[j].cost]) { d[e[j].v]=d[e[j].u]+d[e[j].cost]; } } } //检测负权回路 for(int i=0;i d[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
迪杰斯特拉不支持负边权
#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.松弛
#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.每对顶点间的最短路径
5.最大流a.
可以用动规来做,迪杰斯特拉可以做,表明该问题存在最优子结构,应该可以用动规来做,for【i,for【j,for【组长,for【小于组长1个规模的阵所有最优解】】】】,大约是O(n^4);也可以用for【迪杰斯特拉】来做大约是;也可以for【贝尔曼弗洛德】来做;
b.Floyd-Warshall(O(n^3))
c.稀疏图上的johnson算法#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;k d[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 暂待
回忆时,理解不了,就去看视频,纸质一张图涵盖信息太大,理解起来会有困难的