最小生成树
来源:互联网 发布:c语言比较三个数大小 编辑:程序博客网 时间:2024/06/05 00:24
注:我在修炼当中,博客完全是为了自己复习方便看得,如果你不慎点入了我的博客,看看就好,不要相信,误人子弟就不好了- -
最小生成树有Prim 和 Kruskal 两种经典算法 ,这两个呢都是利用MST性质来构造最小生成树的算法的,如果忘记了MST,去翻我的博客。
先说说prim算法,有个V点集,从中先选出一个点u0放入U点集中,然后找到一条与u0相连代价最小的边,且该边另一个点v0在V - U点集中。此时将该边加入最小生成树的边的集合中,然后将v0加入到U点集中,之后不断重复该操作,直到所有点都加入到了U点集中。
Prim + 优先队列
不会算时间复杂度,GG,T_T,大概是O(nloge)的,注意优先队列时间复杂度为O(logn)的
#include <iostream>#include <queue>#include<cstring>#include<cstdio>using namespace std;typedef struct{ long v; long next; long cost;}Edge;typedef struct{ long v; long cost;}node;bool operator <(const node &a,const node &b){ return a.cost>b.cost;}priority_queue<node> q;const long MAXN=10000;Edge e[MAXN];long p[MAXN];bool vist[MAXN];long m,n;long from,to,cost;void init(){ memset(p,-1,sizeof(p)); memset(vist,0,sizeof(vist)); while (!q.empty()) q.pop(); long i; long eid=0; for (i=0;i<n;++i) { scanf("%ld %ld %ld",&from,&to,&cost); e[eid].next=p[from]; e[eid].v=to; e[eid].cost=cost; p[from]=eid++; //以下适用于无向图 swap(from,to); e[eid].next=p[from]; e[eid].v=to; e[eid].cost=cost; p[from]=eid++; }}void Prim(){ long cost=0; init(); node t; t.v=from;//选择起点 t.cost=0; q.push(t); long tt=0; while (!q.empty()&&tt<m) { t=q.top(); q.pop(); if (vist[t.v]) { continue; } cost+=t.cost; ++tt; vist[t.v]=true; long j; for (j=p[t.v];j!=-1;j=e[j].next) { if (!vist[e[j].v]) { node temp; temp.v=e[j].v; temp.cost=e[j].cost; q.push(temp); } } } printf("%ld\n",cost);}int main(){ while (scanf("%ld %ld",&m,&n)!=EOF) //m 代表点 n代表边数 { Prim(); } return 0;}
Prim
时间复杂度是O(n2),与边数无关,适合求边稠密的网。
int minTree(int n){ int i,j; memset(v,0,sizeof(v)); v[0]=1; sum=0; for(i=1;i<n;i++) { min=max; for(j=0;j<n;j++) { if(!v[j]&&map[0][j]<min) { min=map[0][j]; flag=j; } } sum+=min; v[flag]=1; for(j=0;j<n;j++) { if(!v[j]&&map[0][j]>map[flag][j]) { map[0][j]=map[flag][j]; } } } return sum;}
判断次小生成树
#include <iostream>using namespace std;#define MAX 101#define INF 999999999#define max(a,b) (a>b?a:b)int dis[MAX], pre[MAX];int edge[MAX][MAX];int maxVal[MAX][MAX];bool inTree[MAX][MAX];bool vis[MAX];int Prime ( int n ){ int i, j, k, minc, mst; for ( i = 1; i <= n; i++ ) { dis[i] = edge[1][i]; vis[i] = false; pre[i] = 1; } dis[1] = mst = 0; vis[1] = true; for ( i = 2; i <= n; i++ ) { minc = INF; k = -1; for ( j = 1; j <= n; j++ ) { if ( ! vis[j] && dis[j] < minc ) { minc = dis[j]; k = j; } } if ( minc == INF ) return -1; // 图不连通,没有找到最小生成树 mst += minc; vis[k] = true; inTree[pre[k]][k] = inTree[k][pre[k]] = true; // 记录加入的树中的边 for ( j = 1; j <= n; j++ ) if ( vis[j] == true ) maxVal[j][k] = max ( maxVal[j][pre[k]], edge[pre[k]][k] ); // 找j-k的路径上权值最大的那条边,并记录在maxVal[j][k]中 for ( j = 1; j <= n; j++ ) { if ( ! vis[j] && dis[j] > edge[k][j] ) { dis[j] = edge[k][j]; pre[j] = k; // 修正前驱 } } } return mst;}void initial ( int n ){ for ( int i = 1; i < n; i++ ) { for ( int j = i + 1; j <= n; j++ ) { edge[i][j] = edge[j][i] = INF; inTree[i][j] = inTree[j][i] = 0; maxVal[i][j] = maxVal[j][i] = 0; } }} int main(){ int t, n, m, u, v, w; scanf("%d",&t); while ( t-- ) { scanf("%d%d",&n,&m); initial ( n ); while ( m-- ) { scanf("%d%d%d",&u,&v,&w); edge[u][v] = edge[v][u] = w; } int mst = Prime ( n ); if ( mst < 0 ) { printf("0\n"); continue; } int res; bool flag = false; for ( int i = 1; i < n; i++ ) { for ( int j = i + 1; j <= n; j++ ) { if ( inTree[i][j] || edge[i][j] == INF ) continue; // 边edge[i][j]在树中或者i,j之间无边 res = mst + edge[i][j] - maxVal[i][j]; // 用边edge[i][j], 替换i-j路径上权值最大的那条边,得到一棵新的生成树 if ( res == mst ) { flag = true; break; } } if ( flag ) break; } if ( flag ) printf("Not Unique!\n"); else printf("%d\n",mst); } return 0;}
Kruskal
该算法是初始时所有点自成一个连通分量,然后在所有边中选择一条权重最小的边放入边集中,然后再寻找下一条最小的边,并且将该边加入边集的条件是该边
时间复杂度为O(eloge),适合边稀疏的网
#include<iostream>//这里的n代表节点数,给节点初始化,m代表边数,需要给边数排序,#include<stdio.h>#include<string.h>//kruskal算法主要用的是并查集#include<algorithm>using namespace std;int inf=999999;int fa[110000];int n,m;struct node{ int u,v,w;}q[110000];void make_set(){ for(int i=1;i<=n;i++) { fa[i]=i; }}int Find(int x){ if(x!=fa[x]) fa[x]=Find(fa[x]); return fa[x];}bool cmp(node x,node y){ return x.w<y.w;}int kru(){ int ans=0,cnt=0; make_set(); sort(q+1,q+m+1,cmp);//排序要从起始地址,到终止地址此题中i是从1开始的, for(int i=1;i<=m;i++) { int fx=Find(q[i].u); int fy=Find(q[i].v); if(fx!=fy) { fa[fx]=fy; ans+=q[i].w; cnt++; } } return ans;}int main(){ while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=m;i++) { scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].w); } printf("%d\n",kru()); } return 0;}
0 0
- 最小比例 最小生成树
- 最小生成树&&次最小生成树
- 最小生成生成树计数
- 树+最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树Kruskal
- kruskal 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树问题
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 51nod1405(树形dp)
- iOS中锁定竖屏不让其横屏的方法
- LayoutAnimationController为视图添加动画效果
- CSS 的继承、层叠和特殊性[修改版]
- Apache Maven 入门篇 ( 上 )
- 最小生成树
- 自定义个TabLayout
- Servlet 基础02
- POJ 2828 排队插队(线段树_好题)
- 异常捕获try catch的使用
- 无插件实现WordPress面包屑解决方案
- javascript基础
- 牛顿迭代法
- Qt编写串口通信程序 讲解