次小生成树模板

  1 kruskal
  2 #include <vector>
  3 #include <iostream>
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <algorithm>
  7 #define INF 0x3f3f3f3f
  8
  9 using namespace std;
 10 int n,m;
 11 struct data
 12 {
 13     int u,v,w;
 14     bool vis;
 15 } p[20010];
 16 vector<int>G[110];
 17 int per[110],maxd[110][110];
 18 bool cmp(data a,data b)
 19 {
 20     return a.w < b.w;
 21 }
 22 int Union_Find(int x)
 23 {
 24     return x == per[x] ? x: per[x] = Union_Find(per[x]);
 25 }
 26 void kruskal()
 27 {
 28     sort(p,p+m,cmp);
 29     for(int i=0; i<=n; i++)//初始化
 30     {
 31         G[i].clear();
 32         G[i].push_back(i);
 33         per[i]=i;
 34     }
 35     int sum=0,k=0;//sum是最小生成树的值
 36     for(int i=0; i<m; i++){
 37         if(k==n-1)  break;
 38         int x1=Union_Find(p[i].u),x2=Union_Find(p[i].v);
 39         if(x1!=x2){
 40             k++;
 41             p[i].vis=1;//这条边已经用过了
 42             sum+=p[i].w;
 43             int len_x1=G[x1].size();
 44             int len_x2=G[x2].size();
 45             for(int j=0; j<len_x1; j++)   //更新两点之间距离的最大值
 46             for(int k=0; k<len_x2; k++)
 47             maxd[G[x1][j]][G[x2][k]]=maxd[G[x2][k]][G[x1][j]]=p[i].w;//因为后面的边会越来越大,所以这里可以直接等于当前边的长度
 48             per[x1]=x2;
 49             //因为per[x1] = x2,在Union_Find函数中要寻找和x1相关联节点的跟节点的时候,都会找到x2,所以这里不用再去更新和x1节点相连的节点
 50             //十分感谢Self-Discipline博主,提出此问题
 51 //            int tem[110];
 52 //            for(int j=0; j<len_x2; j++)//现在已经属于一棵树了,那么我们就将点添加到相应的集合中
 53 //                tem[j]=G[x2][j];
 54             for(int j=0; j<len_x1; j++)
 55                 G[x2].push_back(G[x1][j]);
 56 //            for(int j=0; j<len_x2; j++)
 57 //                G[x1].push_back(tem[j]);
 58         }
 59     }
 60     int cisum=INF;//次小生成树的权值
 61     for(int i=0; i<m; i++)
 62         if(!p[i].vis)
 63             cisum=min(cisum,sum+p[i].w-maxd[p[i].u][p[i].v]);
 64     if(cisum>sum)
 65         printf("%d\n",sum);
 66     else
 67         printf("Not Unique!\n");
 68 }
 69 int main()
 70 {
 71     int T;
 72     scanf("%d\n",&T);
 73     while(T--){
 74         scanf("%d%d",&n,&m);
 75         for(int i=0; i<m; i++){
 76             scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
 77             p[i].vis = false;
 78         }
 79         kruskal();
 80     }
 81     return 0;
 82 }
 83
 84 prim
 85 #include<iostream>
 86 #include<string>
 87 #include<cstdio>
 88 #include<map>
 89 #include<cstring>
 90 #include<cmath>
 91 #include<algorithm>
 92 using namespace std;
 93 const int INF=99999999;
 94 const int N=1010;
 95 struct point
 96 {
 97     int x,y;
 98 } p[N];
 99 double G[N][N],dist[N];
100 double path[N][N];//从i到j的路径上最大边的权值
101 int population[N];//每个城市的人口数
102 int pre[N],visit[N];
103 bool used[N][N];//边是否在该MST中
104 int n;
105 inline double Dist(point v1,point v2)
106 {
107     return sqrt(double(v1.x-v2.x)*(v1.x-v2.x)+double(v1.y-v2.y)*(v1.y-v2.y));
108 }
109 double Prim()
110 {
111     double Mst=0;
112     memset(visit,0,sizeof(visit));
113     memset(used,0,sizeof(used));
114     memset(path,0,sizeof(path));
115     visit[1]=1;
116     for(int i=1; i<=n; ++i){
117         dist[i] = G[1][i];
118         pre[i] = 1;
119     }
120     for(int i=1; i<n; ++i){
121         int u=-1;
122         for(int j=1; j<=n; ++j){
123             if(!visit[j]){
124                 if(u==-1||dist[j]<dist[u])
125                     u=j;
126             }
127         }
128         used[u][pre[u]]=used[pre[u]][u] = true;//加入MST
129         Mst+=G[pre[u]][u];
130         visit[u]=1;
131         for(int j=1; j<=n; ++j){
132             if(visit[j]&&j!=u)//求从u到j的路径上最大边的权值
133             {
134                 path[u][j]=path[j][u]=max(path[j][pre[u]],dist[u]);
135                 //printf("path[j][pre[u]]:%lf\n",path[j][pre[u]]);
136             }
137             if(!visit[j]){
138                 if(dist[j]>G[u][j])//更新相邻顶点的dist
139                 {
140                     dist[j]=G[u][j];
141                     pre[j]=u;
142                 }
143             }
144         }
145     }
146     return Mst;
147 }
148 int main()
149 {
150     int tcase;
151     scanf("%d",&tcase);
152     while(tcase--){
153         scanf("%d",&n);
154         memset(G,0,sizeof(G));
155         for(int i=1; i<=n; ++i)
156             scanf("%d%d%d",&p[i].x,&p[i].y,&population[i]);
157         for(int i=1; i<=n; ++i){
158             for(int j=1; j<=n; ++j){
159                 if(i!=j)
160                     G[i][j]=Dist(p[i],p[j]);
161             }
162         }
163         double Mst=Prim();
164         double res=-1;
165         for(int i=1; i<=n; ++i){
166             for(int j=1; j<=n; ++j)
167                 if(i!=j){
168                     if(used[i][j])
169                         res=max(res,(population[i]+population[j])/(Mst-G[i][j]));
170                     else
171                         res=max(res,(population[i]+population[j])/(Mst-path[i][j]));
172                 }
173         }
174         printf("%.2f\n",res);
175     }
176     return 0;
177 }

原文地址:https://www.cnblogs.com/pangbi/p/11614445.html

时间: 2024-10-10 09:04:59

次小生成树模板的相关文章

poj 2831 次小生成树模板

/*次小生成树 题意:给你一些路径,现在将一部分路径权值减少后问是否可以替代最小生成树里面的边. 解:次小生成树,即将这条边连上,构成一个环 求出任意两点路径之间的除了这条边的最大值,比较这个最大值>=这条边,说明可以替换. prime算法次小生成树模板 */ #include<stdio.h> #include<string.h> #define N 1100 #define inf 0x3fffffff int ma[N][N]; int Min(int a,int b)

POJ_1679_The Unique MST(次小生成树模板)

The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 23942   Accepted: 8492 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undire

uva10600次小生成树模板题

裸题,上模板就行,注意j  !  =  k #include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<cassert> #include<iomanip> #include<cstdlib> #include&

洛谷 P4180 【模板】严格次小生成树[BJWC2010]【次小生成树】

严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点的路径上的最长边,如果最长边等于枚举到的边的边权,那么选次长边(没有次长边的话直接跳过),然后在最小生成树的权值上减去路径上最/次长边,加上当前枚举的边的边权 因为如果加入枚举的边的,那么就形成了一个环,需要断开一条边 注意一开始单点次小值赋为0 #include<iostream> #inclu

POJ 1679 prime次小生成树判定生成树是否唯一

The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 21931   Accepted: 7784 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undire

[BJOI 2010]次小生成树Tree

Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值)  这下小 C 蒙了,他找到了你,希望你帮他解决这个问题. Input 第一行包含两个整数N 和M,表示无向图

图论——次小生成树

次小生成树模板 通过poj 1679 #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <math.h> #include <stack> #include <queue> #include <set> using namespace std; #define INF 10000000

一本通1555【例 4】次小生成树

1555:[例 4]次小生成树 时间限制: 1000 ms         内存限制: 524288 KB 题目描述 原题来自:BeiJing 2010 组队赛 给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树. 设最小生成树的边权之和为 sum,严格次小生成树就是指边权之和大于 sum 的生成树中最小的一个. 输入格式 第一行包含两个整数 N 和 M,表示无向图的点数与边数: 接下来 MM 行,每行三个数 x,y,z,表示点 x 和点 y 之间有一条边,边的权值为 z. 输出格式

Luogu P4180 【模板】严格次小生成树[BJWC2010]

P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得意之时,小\(P\)又来泼小\(C\)冷水了.小\(P\)说,让小\(C\)求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是\(E_M\),严格次小生成树选择的边集是\(E_S\),那么需要满足:(\(value(e)\)表示边\(e\)的权值)\