【模板】 次小生成树

 1 /*for(遍历图中所有不属于最小生成树的边)
 2     把当前边加入最小生成树产生回路
 3     去掉回路中除当前边之外权值最大的边
 4     记录下现在的树及其总权值
 5 在上面循环产生的树中选一棵总权值最小的,就是次小生成树*/
 6 /*上面做法只遍历一次最小生成树,但是如果枚举删去最小生成树上的边,那就要求n-2次最小生成树了,所以不可取*/
 7 #include <cstdio>
 8 #include <cstring>
 9 #include <algorithm>
10 #include<queue>
11 using namespace std;
12 typedef pair<int,int> pii;
13 const int maxn = 111;
14 const int inf = 0x3f3f3f3f;
15 int g[maxn][maxn];//邻接矩阵存图
16 int Max[maxn][maxn];//表示最小生成树中i到j的最大边权
17 bool used[maxn][maxn];//判断该边是否加入最小生成树
18 int pre[maxn];//点在最小生成树上的前驱
19 int dis[maxn];//在已存的点集中,到各个点的最短边
20 bool vis[maxn];//判断该点是否加入最小生成树
21 int T,n,m;
22 int prim()
23 {
24     int sum= 0;
25     memset(vis, false, sizeof(vis));
26     memset(used, false, sizeof(used));
27     memset(Max, 0, sizeof(Max));
28     memset(dis,0x3f3f3f3f,sizeof(dis));
29     dis[1]=0;
30     pre[1]=0;
31     priority_queue<pii,vector<pii>,greater<pii> >q;
32     q.push(make_pair(0,1));
33     int all=0;
34     while(!q.empty()){
35         int u=q.top().second;
36         q.pop();
37         if(vis[u]) continue;
38         vis[u]=1;
39         //就是只有当我确定了u这个点进入了最小生成树,我才改used数组和Max,之间都只是根据dis修改pre;
40         used[u][pre[u]]=used[pre[u]][u]=1;
41         ++all;
42         sum+=dis[u];
43         for(int j=1;j<=n;++j){
44             if(vis[j]) {
45                 if(j!=u) Max[j][u]=Max[u][j]=max(Max[j][pre[u]],dis[u]);
46                 else Max[j][u]=0;
47             //相当于一个dp,求出j到u之间最长边的边权.
48             }
49             else if(g[j][u]!=0x3f3f3f3f&&dis[j]>g[j][u]){
50                 dis[j]=g[j][u];
51                 pre[j]=u;
52                 q.push(make_pair(dis[j],j));
53             }
54         }
55     }
56     if(all<n) return -1;
57     return sum;//最小生成树的权值之和
58 }
59 int smst(int sum)//sum是最小生成树的权值和
60 {
61     int ans=0x3f3f3f3f;
62     for (int i = 1; i <= n; i++)//枚举最小生成树之外的边
63         for (int j = i + 1; j <= n; j++)
64             if (g[i][j]!=0x3f3f3f3f&&!used[i][j])
65             //加一条连接i和j(保证之后可以构成生成树)的且不在最小生成树的边,再删去i和j中最大边权的边
66                 ans=min(ans,sum+g[i][j]-Max[i][j]);
67     if (ans==0x3f3f3f3f) return -1;
68     return ans;
69 }
70 int main()
71 {
72     scanf("%d", &T);
73     while (T--)
74     {
75         scanf("%d %d", &n, &m);
76         memset(g,0x3f3f3f3f,sizeof(g));
77         for(int i=1;i<=n;++i) g[i][i]=0;
78         int u,v,w;
79         for(int i=1;i<=m;++i){
80             scanf("%d%d%d",&u,&v,&w);
81             g[u][v]=g[v][u]=min(g[u][v],w);
82         }
83         int ans=prim();
84         if(ans==-1) puts("Not Unique!");
85         else if(smst(ans)==ans) puts("Not Unique!");
86         else printf("%d\n",ans);
87         //题目要判断最小生成树是否唯一
88     }
89     return 0;
90 }

原文地址:https://www.cnblogs.com/xiaobuxie/p/11391892.html

时间: 2024-08-01 11:53:48

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

洛谷.4180.[模板]次小生成树Tree(Kruskal LCA 倍增)

构建完MST后,枚举非树边(u,v,w),在树上u->v的路径中找一条权值最大的边(权为maxn),替换掉它这样在 w=maxn 时显然不能满足严格次小.但是这个w可以替换掉树上严格小于maxn的次大边用倍增维护MST上路径的最大值.次大值,每条非树边的查询复杂度就为O(logn) ps:1.倍增更新次大值时,未必是从最大值转移,要先赋值较大的次大值,再与较小的那个最大值比较.2.maxn!=w时,是可以从maxn更新的(不能更新就是上面情况啊)倍增处理部分我还是在dfs里写吧 md改了一晚上

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

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)

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

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

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

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

次小生成树【模板】

给一个图,判断图的最小生成树是否唯一. End[]记录邻接表尾节点的位置.MST表示最小生成树的大小,SecMST表示次小生成树的大小. #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 1010; const int MAXM = 100010; int father[MAXN]; i

poj 1679 The Unique MST 【次小生成树】【模板】

题目:poj 1679 The Unique MST 题意:给你一颗树,让你求最小生成树和次小生成树值是否相等. 分析:这个题目关键在于求解次小生成树. 方法是,依次枚举不在最小生成树上的边,然后添加到最小生成树上,然后把原树上添加了之后形成环的最长的边删去,知道一个最小的.就是次小生成树. 这些需要的都可以在求解最小生成树的时候处理出来. AC代码: #include <cstdio> #include <cstring> #include <iostream> #i

cogs P1578【模板】 次小生成树初级练习题

1578. 次小生成树初级练习题 ☆   输入文件:mst2.in   输出文件:mst2.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 求严格次小生成树 [输入格式] 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z. [输出格式] 包含一行,仅一个数,表示严格次小生成树的边权和.(数据保证必定存在严格次小生成树) [样例输入] 5 6 1 2 1 1 3 2 2 4 3

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

传送门 次小生成树 那肯定是最小生成树上改一条边(改两条肯定不如只改其中一条小) 那就枚举所有不在最小生成树上的边 考虑如果把此边加入,另一边删除后的情况 考虑要删哪条边后才能保持树的形态,并且总长最小 加入一条边后树就会出现一个环 那么删掉的边要在加入的边连接的两点间的路径上 并且删去的边要尽量大 那就可以用LCA来求出树上两点间路径上的最长边 但是现在还有一个问题,可能删去的边和加入的边一样长 所以还要维护一下次长的边 次长边维护也不难,具体看代码 #include<iostream> #