图论-Kurskal,Dijkstra,spfa,最小生成树整理
Kurskal算法-
Kurskal算法的核心是排序与利用并查集来维护一个联通的树。
我们要利用并查集的find函数来查找两个点的祖先是否为同一个点。
因为算法在进行并查集维护的时候是按边权从小到大来便利的,所以,相连的树很有可能是两个互不相干的集合。
判断两个点的祖先是否是同一个,如果是同一个的话,那么说明他们两个已经相联通则不进行操作。
//边结构体
struct Edge { int u,v,w;//点u与点v相连,权值为w。 }如果两个点的祖先不同,则说明这两个点不相互联通,把其中一个点的祖先改变为另一个点的祖先。
当所联通的结点达到了总结点数的时候,退出操作。
1 int find(int x)//find函数 2 { 3 if(fa[x]==x) return x; 4 return fa[x]=find(fa[x]); 5 }如此,Kurskal算法就完成了。
View Code1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 #define maxn 10000 5 int fa[maxn],n,ans; 6 int find(int x) 7 { 8 if(fa[x] == x) return x; 9 return fa[x]=find(fa[x]); 10 } 11 struct edge 12 { 13 int u,v,w; 14 }Edge[maxn]; 15 bool cmp(edge a,edge b) 16 { 17 return a.w<b.w; 18 } 19 int main() 20 { 21 scanf("%d",&n); 22 for(int i=1;i<=n;i++) 23 { 24 int x,y,w; 25 scanf("%d%d%d",&x,&y,&w); 26 Edge[i].u=x; 27 Edge[i].v=y; 28 Edge[i].w=w; 29 fa[x]=x;fa[y]=y; 30 } 31 sort(Edge+1,Edge+n+1,cmp); 32 for(int i=1;i<=n;i++) 33 { 34 int u=Edge[i].u,v=Edge[i].v,w=Edge[i].w; 35 if(find(u)==find(v)) continue; 36 fa[find(u)]=v; 37 ans+=w; 38 printf("u=%d v=%d\n",u,v); 39 } 40 printf("%d",ans); 41 return 0; 42 }
Dijkstra算法-
有两个集合一个为s表示已经求出其最短路径点的集合,另一个集合为u表示没有求出其最短路径点的集合
可以理解为贪心。
开始的时候把起点丢进s集合中,搜索和u相连的所有边,找到其中在u集合中最短的点相连的边,把这个点当为中转点
判断dis[u]+g[u][v]是否小于dis[v]如果小于,就把dis[v](从起点到v点的最小值)替换为dis[u]+g[u][v]。
重复上述步骤,直到所有点都进入到s集合中结束。
View Code1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define Maxn 1000 6 int g[Maxn][Maxn];//邻接矩阵储存图 7 int tmp,dis[Maxn];//tmp记录有多少个点,dis表示起点f到e点的最小值。 8 bool vis[Maxn];//表示每个点是否已经走过 9 int dijkstar(int f,int e)//起点f,终点e 10 { 11 for(int i=1;i<=tmp;i++)//初始化dis 12 { 13 dis[i]=g[f][i]; 14 vis[i]=0; 15 } 16 dis[f]=0; 17 vis[f]=1;//标记f点 18 for(int i=1;i<=tmp;i++) 19 { 20 int Min=2147483647,p=0; 21 for(int j=1;j<=tmp;j++) 22 if(!vis[j]&&dis[j]<Min) 23 Min=dis[j],p=j; 24 vis[p]=1; 25 for(int j=1;j<=tmp;j++) 26 if(!vis[j]&&dis[j]>dis[p]+g[p][j]) 27 dis[j]=dis[p]+g[p][j]; 28 } 29 return dis[e]; 30 } 31 int main() 32 { 33 int n; 34 scanf("%d",&n); 35 memset(g,0x3f,sizeof g); 36 for(int i=1;i<=n;i++) 37 { 38 int x,y,w; 39 scanf("%d%d%d",&x,&y,&w); 40 g[x][y]=g[y][x]=w; 41 tmp=max(x,max(tmp,y)); 42 } 43 int ans=dijkstar(fitst,end);//first为起点,end为终点 44 printf("%d",ans); 45 return 0; 46 }
Spfa算法-
感觉核心就是搜索,在这里给出BFS版本的Spfa。
利用链式前向星来遍历,这里给出代码。
1 struct Edge 2 { 3 int next,to,w; 4 }edge[Maxn]; 5 void add(int u,int v,int w) 6 { 7 edge[cnt].w=w; 8 edge[cnt].to=v; 9 edge[cnt].next=head[u]; 10 head[u]=cnt++; 11 }我们用一个dis数组来表示从起点u到v点的最短路径,一个bool型vis数组来表示这个点是否已经入队。
所以我们先把dis数组全部初始为极大值。
一个队列q,把起点u入队,dis[u]初始为0,vis[u]=true,u入队。
开始搜索。
让队头值出队,再搜索与队头点相连的所有点,如果dis[队头点]+所相连点 边的权值小于dis[相连点] 的话,更新dis[相连点]=其两点间边的权值。同时判断这个点有没有在队列中,如果没有,则入队。
直到队列中没有任何数后,退出。
这样的话,我们就可以找到从起点u到任意一点v的最短路径值了。
View Code1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <algorithm> 5 using namespace std; 6 #define Maxn 1000 7 int head[Maxn],cnt=1,n,tmp; 8 int vis[Maxn],dis[Maxn]; 9 struct Edge 10 { 11 int to,next,w; 12 } edge[Maxn]; 13 14 void add(int u,int v,int w) 15 { 16 edge[cnt].to=v; 17 edge[cnt].w=w; 18 edge[cnt].next=head[u]; 19 head[u]=cnt++; 20 } 21 void spfa(int u) 22 { 23 queue<int> q; 24 memset(dis,0x3f,sizeof dis); 25 dis[u]=0; 26 vis[u]=1; 27 q.push(u); 28 while(!q.empty()) 29 { 30 int t=q.front(); 31 q.pop(); 32 vis[t]=0; 33 for(int i=head[t];i;i=edge[i].next) 34 { 35 int tmp=edge[i].to; 36 if(dis[tmp]>dis[t]+edge[i].w) 37 { 38 dis[tmp]=dis[t]+edge[i].w; 39 if(!vis[tmp]) 40 { 41 q.push(tmp); 42 vis[tmp]=1; 43 } 44 } 45 46 } 47 } 48 } 49 int main() 50 { 51 scanf("%d",&n); 52 for(int i=1;i<=n;i++) 53 { 54 int x,y,z; 55 scanf("%d%d%d",&x,&y,&z); 56 add(x,y,z); 57 add(y,x,z); 58 tmp=max(x,max(tmp,y)); 59 } 60 spfa(1); 61 printf("%d",dis[7]); 62 return 0; 63 }
Floyd算法-
假如有3个点 x, x1 x2.
x与x2相连边权为a,x与x1相连边权为b,x1与x2相连边权为c。
这时我们比较a是否大于b+c。
如果a>b+c则说明比起从x点直接到x2点来说,从x点先到x1点再周转到x2点所走的距离更短。
如此我们可以遍历每一个点和边利用一个中专值k来表示上述的过程。
用邻接矩阵来储存的话,最终u点到v点的最短路径就是f[u][v](f数组储存图)
核心代码:(大三层循环)
1 for(int k=1;k<=n;k++) 2 for(int i=1;i<=n;i++) 3 for(int j=1;j<=n;j++) 4 f[i][j]=min(f[i][j],f[i][k]+f[k][j]);


浙公网安备 33010602011771号