上次老师检查笔记时,我的第五章笔记还没有整理完整,后来又进行了补充,请老师再看一看:https://www.cnblogs.com/dean-SunPeishuai/p/10674881.html
图
1.邻接矩阵实现
邻接矩阵的构建:
Mgraph<T>::Mgraph(T a[], int n, int e)//邻接矩阵的构建 { vertex = n; arcnum = e; for (int i = 0; i < vertexnum; i++)//初始化顶点 { vertex[i] = a[i]; } memset(arc,0,sizeof(arc)); for (int i = 0; i < arcnum; i++) { int x,y; scanf("%d%d",&x,&y); arc[x][y]=1; arc[y][x]=1; } }
深度优先搜索:
template<class T> void Mgraph<T>::DFS(int v) { cout << vertex[v] << " "; visit[v] =1; for (int i = 0; i < vertexnum; i++) { if (arcnum[v][i] == 1 && visit[i] == 0) DFS(i); } }
广度优先深搜:
template<class T> void Mgraph<T>::BFS(int v) { int Queue[MaxSize]; int front = rear = -1;//借助数组模拟队列先进先出的功能 cout << vertex[v] << " "; visit[v] = 1; Queue[++rear] = 1; while (front != rear) { v = queue[++front]; for (int i = 0; i < vertexnum; i++) { if (visit[i] == 0 && arc[v][i] == 1) { cout << vertex[i] << " "; visit[i] = 1; Queue[++rear] = i; } } } }
2.邻接链表实现(未定义visit[],仅将代码流程过一遍)
#include<bits/stdc++.h> using namespace std; template<class T> struct ArcNode//边表 { int adjvex; ArcNode *next; }; template<class T>//顶点表 struct VertexNode { T vertex; ArcNode *firstedge; }; const int MaxSize = 100; //图的最大顶点数 template <class T> class ALGraph { public: ALGraph(T a[], int n, int e); ~ALGraph; void DFSTraverse(int v); void BFSTraverse(int v); private: VertexNode adjlist[MaxSize]; int vertexNum, arcNum; }; /* 构建函数 */ template<class T> ALGraph<T>::ALGraph(T a[], int n, int e) { vertexNum = n; arcNum = e; for (int i = 0; i < vertexNum; i++) { adjlist[i].vertex = a[i]; adjlist[i].firstedge = NULL; } for (int j = 0; j < arcNum; j++) { int x, y; cin >> x >> y; s = new ArcNode<T>;//生成邻接点序号y的边表节点s s->adjvex = y;//j将边表s插入到第x个边表的头部 s->next = adjlist[x].firstedge; djlist[x].firstedge = s; } } /* 深度优先遍历 */ template<class T> void ALGraph<T>::DFSTraverse(int v) { cout << adjlist[v].vertex; visit[v] = 1; ArcNode<T> p = adjlist[v].firstedge; while (p) { int j = p.adjvex; if (vistt[j] == 0) DFSTraverse(j); p = p->next; } } /* 广度优先搜索 */ template<class T> void ALGraph<T>::BFSTraverse(int v) { int Q[MaxSize]; memset(Q, 0, sizeof(Q)); int front = rear = -1; cout << adjlist[v].vertex; visit[v] = 1; Q[++rear] = v; while (front!=rear) { v = Q[++front]; ArcNode<T> p = adjlist[v].firstedge; while (p) { int j = p->adjvex; if (visit[j] == 0) { cout << adjlist[j].vertex; visit[j] = 1; Q[++rear] = j; } p = p->next; } } } int main() { }
prime算法:自己之前的理解
Prime算法的思想是枚举各个点能够到到达的所有路,找出他们之间最短的,首先选择一个顶点加入生成树,然后找出一条边加入到生成树,重复n-1次,直到把所有的节点都加入到生成树中,在此算法里面需要一个dis数组,不过它和迪杰斯特拉算法的不同之处在于,迪杰斯特拉的思想是dis[i]表示从1到顶点i的最小距离,而Prime算法中,dis[i]代表每个项点到离他最近的点的距离,然后通过松弛操作得出结果 ,时间复杂度为O(N^2)。
求最小生成树Prime模板:
using namespace std; int dis[108],map1[108][108],vis[108]; #define INF 0x3f3f3f3f int n; int prime() { memset(vis,0,sizeof(vis)); int ans=0,cnt=0,k=0,minn=INF; vis[1]=1; cnt++; while(cnt<n) { minn=INF;///就这个地方忘记了,然后、、、、、、 for(int i=1;i<=n;i++)//查找没有访问过的,距离当前最小生成树最小的边 { if(!vis[i]&&dis[i]<minn) { minn=dis[i]; k=i;//标记下来边的临界点 } } cnt++; vis[k]=1;//标记访问过的点 ans+=dis[k]; for(int j=1;j<=n;j++)///由于新加的点,其他的点到最下生成树的点距离可能变短,更新哪些到最小生成树变短的点 { if(!vis[j]&&dis[j]>map1[k][j]) dis[j]=map1[k][j]; } } return ans; } --------------------- 作者:sean(SunPeishuai) 来源:CSDN 原文:https://blog.csdn.net/SunPeishuai/article/details/84719169 版权声明:本文为博主原创文章,转载请附上博文链接!
poj:6:prim算法求最小生成树
题目: 连接:http://sdau.openjudge.cn/graph/6/
分析:裸的最小生成树
代码:
#include<bits/stdc++.h> using namespace std; int dis[108], map1[108][108], vis[108]; #define INF 0x3f3f3f3f int n, e; void prime() { memset(vis, 0, sizeof(vis)); int ans = 0, cnt = 0, k = 0, minn = INF; vis[1] = 1; cnt++; while (cnt < n) { minn = INF;///就这个地方忘记了,然后、、、、、、 for (int i = 1; i <= n; i++) { if (!vis[i] && dis[i] < minn) { minn = dis[i]; k = i; } } cout << minn << " "; cnt++; vis[k] = 1; ans += dis[k]; for (int j = 1; j <= n; j++)///由于新加的点,其他的点到最下生成树的点距离可能变短,更新哪些到最小生成树变短的点 { if (!vis[j] && dis[j] > map1[k][j]) dis[j] = map1[k][j]; } } } int main() { scanf("%d%d", &n, &e); memset(dis, INF, sizeof(dis)); memset(map1, INF, sizeof(map1)); for(int i=1;i<=n;i++) for (int j = 1; j <= n; j++) { scanf("%d", &map1[i][j]); } for (int i = 1; i <= n; i++) { dis[i] = map1[1][i]; } prime(); cout << endl; system("pause"); return 0; }
Kruskal算法思想:
此算法是求最小生成树的另一只种算法,首先,将图上面的权值按照从小到大的顺序排列,最终连成n-1条边。按照排列好的顺序,在连线的过程中可能会遇到已经连通的点,需要用并查集进行辅助判断两个分量上的点是否已经联通。
此处为Kruskal以前自己总结的模板:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <string> #include <iostream> #include <stack> #include <queue> #include <vector> #include <algorithm> #define mem(a,b) memset(a,b,sizeof(a)) #define N 100+20 #define M 100000+20 using namespace std; struct node { int x; int y; int v; }map1[5008]; int n,m,fa[5008]; int fin(int u) { if(fa[u]==u) return u; else { fa[u]=fin(fa[u]);///并查集的路径压缩 return fa[u]; } } int mix(int a,int b) { int f1=fin(a); int f2=fin(b); if(f1!=f2) { fa[f2]=f1; return 1; } return 0; } int cmp(node a,node b) { return a.v<b.v; } int main() { while(scanf("%d",&n)!=EOF) { int ans=0,cnt=0; if(n==0) break; m=n*(n-1)/2; memset(fa,0,sizeof(fa));/// for(int i=1;i<=m;i++) { scanf("%d%d%d",&map1[i].x,&map1[i].y,&map1[i].v); } sort(map1+1,map1+m+1,cmp); for(int i=1;i<=n;i++)///并查集的初始化 { fa[i]=i; } //kruskal算法 for(int i=1;i<=m;i++)///从小到达枚举边 { if(mix(map1[i].x,map1[i].y))///若加的边构不成环则加上 { cnt++; ans+=map1[i].v; } if(cnt==n-1) break; } printf("%d\n",ans); } return 0; }
5:kruskal算法求最小生成树
题目:连接http://sdau.openjudge.cn/graph/5/
分析:略
代码:
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define N 100+20 #define M 100000+20 using namespace std; struct node { int x; int y; int v; }map1[5008]; int n, m, fa[5008], map2[1000][1000]; int fin(int u)//并查集查找 { if (fa[u] == u) return u; else { fa[u] = fin(fa[u]);///并查集的路径压缩 return fa[u]; } } int mix(int a, int b)//连接 { int f1 = fin(a); int f2 = fin(b); if (f1 != f2) { fa[f2] = f1; if(a<b)//在此处输出一条边的两个连接点 cout << a << " " << b << " "; else { cout << b<< " " << a<< " "; } return 1; } return 0; } int cmp(node a, node b) { return a.v < b.v; } int main() { int n, e, v,cnt=0; scanf("%d%d", &n, &e); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { scanf("%d", &map2[i][j]); } int t = 1; for (int i =1; i <= n-1; i++)//此处为适应模板做的适当处理 for (int j = i+1; j <=n; j++) { map1[t].x = i; map1[t].y = j; if(map2[i][j] != 0 && map2[i][j] != 100){ map1[t].v = map2[i][j]; t++; } } sort(map1 + 1, map1 + 1 + e, cmp); for (int i = 1; i <= n; i++) fa[i] = i;//并查集的初始化 /* kruskal算法 */ for (int i = 1; i <= e; i++)//从小到大枚举边 { if(mix(map1[i].x, map1[i].y)) { cnt++; } if (cnt == n - 1) break; } cout << endl; system("pause"); return 0; }
dijkstra求最短路径:‘
题目:http://sdau.openjudge.cn/graph/1/
分析:直接套模板就行,自己之前刘汝佳的模板忘记怎么用输出路径了,尴尬。就从网上扒了一个模板改的。
代码:
#include<stdio.h> #include<string.h> #define INF 1e9 #define maxn 1001 bool vis[maxn]; int adj[maxn][maxn],dis[maxn],pre[maxn];//pre[]记录前驱 int n, m; void dijkstra(int v) { int i, j, u , min; for(i=0;i<n;i++)///v到所点的距离初始化 { dis[i]=adj[v][i]; vis[i]=0; if(i!=v&&adj[v][i]!=INF)pre[i] = v; else pre[i] = -1; } vis[v]=1;dis[v]=0; for(i=0;i<n;i++) { min = INF; for(j=0;j<n;j++) { if(!vis[j]&&min > dis[j]) { min = dis[j]; u = j; } } if(min == INF)break; vis[u]=1; for(j=0;j<n;j++) { if(!vis[j]&&adj[u][j]!=INF&&dis[u]+adj[u][j]<dis[j]) { dis[j] = adj[u][j] + dis[u]; pre[j] = u; } } } } int main() { int start,end1, x, y, w; scanf("%d%d",&n,&m);///n个节点,m条边 scanf("%d%d",&start,&end1);///起点--->终点 for(int i=0;i<n;i++)///初始化 { for(int j=0;j<n;j++) if(i==j)adj[i][j]=0; else adj[i][j] = INF; } while(m--) { scanf("%d%d%d",&x,&y,&w); adj[x][y] = w; } dijkstra(start);///起点 if(dis[end1]==1e9){ printf("no answer\n"); }else{ printf("%d\n",dis[end1]); //以下为输出路径 int p, len=0, ans[maxn]; p = end1; while(p!=0) { ans[len++] = p; p = pre[p]; } printf("v%d ",start); for(int i=len-1;i>=0;i--) printf("v%d ",ans[i]); } return 0; }
floyd求最短路径
题目:http://sdau.openjudge.cn/graph/2/
分析:略
代码:
/*floyd算法,打印路径模板*/ #include <iostream> #include <cstdio> #include <cstring> #include <map> #include <algorithm> #define N 1005 #define INF 0x3f3f3f3f using namespace std; int mapp[N][N], path[N][N];//path[i][j]的含义:从i到j的路径中,i的下一个点。 int n,m;//顶点数,边数 void init() { int i, j; for (i = 0; i < n; i++) for (j = 0; j <n; j++) { if (i == j) mapp[i][j] = 0; else mapp[i][j] = INF; } } void floyd() { for (int i = 0; i <N; ++i) { for (int j = 0; j < N; ++j) { if (mapp[i][j] == INF) path[i][j] = -1;///i不能直接到j else path[i][j] = j;///i到j路径的下一个点为j } } int i, j, k; for (k = 0; k <n; k++) { for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { if (mapp[i][k] < INF && mapp[k][j] < INF && mapp[i][j] > mapp[i][k] + mapp[k][j]) { mapp[i][j] = mapp[i][k] + mapp[k][j]; path[i][j] = path[i][k];//从i到j的下一个顶点为i到k的下一个顶点 } } } } } int main() { scanf("%d%d", &n, &m); int a, b, c; init(); for (int i = 0; i < m; i++) { scanf("%d%d%d", &a, &b, &c); mapp[a][b]=c;//无向图 } floyd();//打印路径 int T, start, end; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(i!=j) { start=i; end=j; if(mapp[start][end]==INF) { cout<<"no answer"<<endl; } else { printf("%d ",mapp[start][end]); int tmp = start; printf("v%d ",start); while (tmp!= end) { printf("v%d ",path[tmp][end]); tmp = path[tmp][end]; } } printf("\n"); } } } return 0; }