生成树
prim算法和kruskal算法是解决生成树的算法,prim更快,但kruskal实现简单,
思路上是贪心:
prim:每次寻找离生成树最近的点,加入生成树,再用那个点松弛其他点到生成树的距离,一般是O(N2);当然,有优化,二叉堆可以到达,斐波那契堆可以优化到
kruskal:给边排序,区最小的边加入就好,用并查集维护联通;时间复杂度为;A是阿克曼函数的反函数,再加V因为并查集要初始化
证明我就不搞了,就是两个反证,意思一下就好啦。
板子还是要上的
1 int prime(int n) 2 { 3 const int INF = 1<<29; 4 int d[maxn]; 5 int k = 1;d[k] = 0; 6 for(int i = 1;i <= n;i++) d[i] = G[1][i]; 7 int vis[maxn];int ans = 0; 8 memset(vis,0,sizeof(vis)); 9 for(int i = 1;i < n;i++) 10 { 11 vis[k] = 1; 12 int M =INF;int last = 0; 13 for(int j = 1;j <= n;j++) 14 { 15 if(d[j] < M&& !vis[j]){ 16 M =d[j]; 17 last = j; 18 } 19 } 20 if(M == INF) break; 21 ans += M; 22 k = last; 23 for(int j = 1;j <= n;j++) 24 if(j != k&&d[j] > G[k][j]) 25 d[j] = G[k][j]; 26 } 27 return ans; 28 };
斐波那契堆的不会:好吧,我还是会用STL的:
1 struct HeapNode{ 2 int d,u; 3 bool operator < (const HeapNode& rhs)const{ 4 return d > rhs.d; 5 } 6 }; 7 int prime(int n) 8 { 9 int ans = 0; 10 priority_queue<HeapNode> Q; 11 Q.push((HeapNode){0,1}); 12 for(int i = 0;i <= n;i++) d[i] = INF; 13 d[1] = 0; 14 Q.push((HeapNode){0,1}); 15 int vis[maxn]; 16 memset(vis,0,sizeof(vis)); 17 while(!Q.empty()){ 18 HeapNode x =Q.top();Q.pop(); 19 int k = x.u; 20 if(vis[k]) continue; 21 vis[k] = 1; 22 ans += x.d; 23 for(int j = 1;j <= n;j++) 24 if(j != k&&d[j] > G[k][j]) 25 { 26 d[j] = G[k][j]; 27 Q.push((HeapNode){d[j],j}); 28 29 } 30 } 31 return ans; 32 };
1 int find(int x) 2 { 3 if(pa[x] == x) return x; 4 return pa[x] = find(pa[x]); 5 } 6 int kruskal(int n,int m) 7 { 8 for(int i = 0;i <= n;i++) pa[i] = i; 9 int ans = 0; 10 sort(edges.begin(),edges.end()); 11 for(int i = 0;i < edges.size();i++) 12 { 13 Edge& e =edges[i]; 14 int x = find(e.from);int y = find(e.to); 15 if(x != y){ 16 pa[x] = y; 17 ans += e.dist; 18 printf("%d %d ",min(e.from,e.to),max(e.from,e.to )); 19 } 20 } 21 return ans; 22 }
建图部分就不要我再贴了吧
结论:瓶颈生成树 无向图G的一颗瓶颈生成树是这样的一颗生成树,它最大的边权值在G的所有生成树中是最小的。瓶颈生成树的值为T中最大权值边的权。
无向图的最小生成树一定是瓶颈生成树,但瓶颈生成树不一定是最小生成树。
命题:无向图的最小生成树一定是瓶颈生成树。
证明:可以采用反证法予以证明。
假设最小生成树不是瓶颈树,设最小生成树T的最大权边为e,则存在一棵瓶颈树Tb,其所有的边的权值小于w(e)。删除T中的e,形成两棵数T', T'',用Tb中连接T', T''的边连接这两棵树,得到新的生成树,其权值小于T,与T是最小生成树矛盾。[1-2]
命题:瓶颈生成树不一定是最小生成树。
下面是一个反例:
从上面可以看出,最小瓶颈生成树不止一条。
最小生成树是最小瓶颈生成树的一个子集。
POJ 2395
直接模板;
POJ 2395
次小生成树
1 #include<iostream> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 #include<cstdio> 6 7 8 using namespace std; 9 10 const int maxn = 101010; 11 int pa[maxn]; 12 13 struct Edge 14 { 15 int from,to,dist; 16 Edge(int from,int to,int dist) :from(from),to(to),dist(dist){} 17 bool operator < (const Edge& b) const{ 18 return dist < b.dist; 19 } 20 }; 21 vector<Edge> edges; 22 int find(int x) 23 { 24 if(pa[x] == x) return x; 25 else return pa[x] = find(pa[x]); 26 } 27 28 int kruskal(int n,int m) 29 { 30 for(int i = 1;i <= n;i++) pa[i] = i; 31 sort(edges.begin() ,edges.end()); 32 int cnt = 0; 33 for(int i = 0;i < m;i++) 34 { 35 Edge& e = edges[i]; 36 int x = find(e.from);int y = find(e.to); 37 if(x != y) 38 { 39 pa[x] = y; 40 cnt++; 41 } 42 if(cnt == n-1) return e.dist ; 43 } 44 } 45 46 int main() 47 { 48 int n,m; 49 scanf("%d%d",&n,&m); 50 for(int i = 0;i < m;i++) 51 { 52 int from,to,dist; 53 scanf("%d%d%d",&from,&to,&dist); 54 edges.push_back(Edge(from,to,dist)); 55 } 56 printf("%d\n",kruskal(n,m)); 57 return 0; 58 }
最小瓶颈生成树:先求最小生成树,处理出所有路径的最大路径,依次加不在最小生成树里的边,肯定形成环,去最长路径,扫描维护一下增量值,因为是自己想的,没做题来验证,估计又慢又丑还不对,还是贴下吧:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<cstdlib> 7 using namespace std; 8 9 struct Edge 10 { 11 int from,to,dist; 12 Edge(int from,int to,int dist):from(from),to(to),dist(dist){} 13 bool operator < (const Edge& rhs)const{ 14 return dist < rhs.dist; 15 } 16 }; 17 const int maxn = 1000; 18 vector<Edge> edges1; 19 vector<int> G1[maxn]; 20 vector<Edge> edges2; 21 vector<int> G2[maxn]; 22 int pa[maxn]; 23 int maxcost[maxn][maxn]; 24 int vis[maxn]; 25 int find(int x) 26 { 27 if(pa[x] == x) return x; 28 else return pa[x] = find(pa[x]); 29 } 30 31 int kruskal(int n) 32 { 33 for(int i = 0;i <= n;i++) pa[i] = i; 34 sort(edges1.begin(),edges1.end()); 35 int m = edges1.size(); 36 int ans = 0;int cnt = 0; 37 for(int i = 0;i < m;i++) 38 { 39 Edge& e = edges1[i]; 40 int x = find(e.from);int y = find(e.to); 41 if(x != y) 42 { 43 pa[x] = y; 44 ans += e.dist; 45 edges2.push_back(Edge(e.from,e.to,e.dist)); 46 edges2.push_back(Edge(e.to,e.from,e.dist)); 47 int m2 = edges2.size(); 48 G2[e.from].push_back(m2-2); 49 G2[e.to].push_back(m2-1); 50 cnt++; 51 } 52 if(cnt == n-1) return ans; 53 } 54 } 55 56 void dfs(int from,int now,int maxdist) 57 { 58 maxcost[from][now] = maxdist; 59 for(int i = 0;i < G2[now].size();i++) 60 { 61 Edge& e = edges2[G2[now][i]]; 62 if(vis[e.to]) continue; 63 int mid = maxdist; 64 maxdist = max(maxdist,e.dist); 65 vis[e.to] = 1; 66 dfs(from,e.to,maxdist); 67 vis[e.to] = 0; 68 maxdist = mid; 69 } 70 return; 71 } 72 73 int main() 74 { 75 int n,m; 76 scanf("%d%d",&n,&m); 77 for(int i = 0 ;i < m;i++) 78 { 79 int from,to,dist; 80 scanf("%d%d%d",&from,&to,&dist); 81 edges1.push_back(Edge(from,to,dist)); 82 edges2.push_back(Edge(to,from,dist)); 83 int k = edges1.size(); 84 G1[from].push_back(k-2); 85 G1[to].push_back(k-1); 86 } 87 int ans = kruskal(n); 88 for(int i = 1;i <= n;i++) 89 { 90 vis[i] = 1; 91 dfs(i,i,0); 92 vis[i] = 0; 93 } 94 int add = 9999999; 95 for(int i = 0;i < m;i++) 96 { 97 Edge& e = edges1[i]; 98 if(e.dist > maxcost[e.from][e.to]) 99 { 100 add = min(e.dist-maxcost[e.from][e.to],add); 101 } 102 } 103 cout<<ans<<endl; 104 cout<<ans+add<<endl; 105 return 0; 106 }
最小增量生成树,暂时不会
最小树形图: 朱刘;妈的毒瘤,搞了好久还是不知道哪里挑错了。

浙公网安备 33010602011771号