URAL - 1416 Confidential (最小生成树与次小生成树)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12614

本文链接:http://www.cnblogs.com/Ash-ly/p/5495851.html

题意:

  给你N个点,以及M条边,让你计算是否存在最小生成树和次小生成树,如果存在打印出权值,否则打印-1.

思路:

  很直接的一道题,关于求次小生成树的方法,在我的另外一篇文章中:http://www.cnblogs.com/Ash-ly/p/5494975.html

代码:

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <algorithm>
  5 #include <cstdio>
  6 #include <string>
  7
  8 using namespace std;
  9 typedef long long LL;
 10
 11 const int MAXN = 500;
 12 const int MAXE = 500 * 500;
 13 const int INF = 0x3f3f3f3f;
 14 int pre[MAXN + 7];
 15
 16 void initPre(int n){ for(int i = 0; i <= n; i++) pre[i] = i; }
 17
 18 //并查集
 19 int Find(int x){ return x == pre[x] ? x : pre[x] = Find(pre[x]); }
 20
 21 void merge(int x, int y){ int fx = Find(x), fy = Find(y); if(fx != fy) pre[fx] = fy; }
 22
 23 struct Edge{ //前向星存边
 24     int u, v; //起点  终点
 25     int w;
 26     bool select;
 27 }edge[MAXE + 7];
 28
 29 bool cmp(Edge a, Edge b){
 30     if(a.w != b.w) return a.w < b.w;
 31     if(a.u != b.u) return a.u < b.u;
 32     return a.v < b.v;
 33 }
 34
 35 struct Node{//链式前向星 用于存储每个集合里面的边
 36     int to;
 37     int next;
 38 }link[MAXN + 7];
 39
 40 int head[MAXN + 7];//邻接表的头结点的位置
 41 int End[MAXN + 7];//邻接表的尾节点的位置
 42 int length[MAXN + 7][MAXN + 7];//最小生成树中任意两点路径上的最长边
 43
 44 int kruskal(int n, int m){
 45     //初始化邻接表,对于每一个顶点添加一个指向自身的边,表示以i为代表元的集合中只有点i
 46     for(int i = 1; i <= n; i++){
 47         link[i].to = i, link[i].next = head[i];
 48         End[i] = i, head[i] = i;
 49     }
 50     sort(edge + 1, edge + 1 + m, cmp);
 51     int cnt = 0;
 52     for(int i = 1; i <= m; i++){
 53         if(cnt == n - 1) break;//当找到的边数等于节点数-1,说明mst已经找到
 54         int fx = Find(edge[i].u);
 55         int fy = Find(edge[i].v);
 56         if(fx != fy){
 57             for(int j = head[fx]; j != -1; j = link[j].next)//修改length数组
 58                 for(int k = head[fy]; k != -1; k = link[k].next)
 59                 //每次合并两个等价类的之后,分别属于两个等价类的两个节点之间的最长边一定是当前加入的边
 60                     length[link[j].to][link[k].to] = length[link[k].to][link[j].to] = edge[i].w;
 61             //合并邻接表
 62             link[End[fy]].next = head[fx];
 63             End[fy] = End[fx];
 64             merge(fx, fy);
 65             cnt++;
 66             edge[i].select = true;
 67         }
 68     }
 69     if(cnt < n - 1) return -1;
 70     return 1;
 71 }
 72
 73 void init(){
 74     memset(length, -1, sizeof(length));
 75     memset(head, -1, sizeof(head));
 76     memset(&edge, 0, sizeof(Edge));
 77     memset(End, 0, sizeof(End));
 78     memset(&link, 0, sizeof(Node));
 79 }
 80
 81 int main(){
 82     //freopen("input.txt", "r", stdin);
 83     int n, m;
 84     while(~scanf("%d%d", &n, &m)){
 85         init();
 86         initPre(n);
 87         for(int i = 1; i <= m; i++) edge[i].select = false;
 88         for(int i = 1; i <= m; i++) scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
 89         int flag = kruskal(n, m);
 90         int mst = 0;
 91         for(int i = 1; i <= m; i++) if(edge[i].select) mst += edge[i].w;//计算出最小生成树
 92         int secmst = INF;
 93         //在 T/(u,v) + (x, y)中寻得次小生成树
 94         for(int i = 1; i <= m; i++) if(!edge[i].select) secmst = min(secmst, mst + edge[i].w - length[edge[i].u][edge[i].v]);
 95         if(flag < 0) printf("Cost: -1\nCost: -1\n");
 96         else if(n == m + 1) printf("Cost: %d\nCost: -1\n", mst);
 97         else printf("Cost: %d\nCost: %d\n", mst, secmst);
 98     }
 99     return 0;
100 }
时间: 2024-10-24 19:49:01

URAL - 1416 Confidential (最小生成树与次小生成树)的相关文章

URAL 1416 Confidential(次小生成树)

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1416 Zaphod Beeblebrox — President of the Imperial Galactic Government. And by chance he is an owner of enterprises that trade in secondhand pens. This is a complicated highly protable and highly comp

Ural 1416 Confidential,次小生成树

不严格次小生成树. 注意图可能不连通. #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn = 505; const int INF = 1e7; bool vis[maxn]; int d[maxn]; int pre[maxn]; int Max[maxn][maxn]; int g[

树的问题小结(最小生成树、次小生成树、最小树形图、LCA、最小支配集、最小点覆盖、最大独立集)

树的定义:连通无回路的无向图是一棵树. 有关树的问题: 1.最小生成树. 2.次小生成树. 3.有向图的最小树形图. 4.LCA(树上两点的最近公共祖先). 5.树的最小支配集.最小点覆盖.最大独立集. 一.最小生成树 解决的问题是:求无向图中边权值之和最小的生成树. 算法有Kruskal和Prim. Kruskal使用前向星和并查集实现,可以存储重边(平行边),时间复杂度是O(m log m  +  m),m是边的数量. Prim使用邻接矩阵建图,不可以存储重边(平行边),如果出现重边,存储的

POJ 1679 The Unique MST 判断最小生成树是否唯一/次小生成树

题目链接: 1679 题意: 给出 M个点N条边 求它的的最小生成树 不唯一则输出:Not Unique! 题解: prim:判断"最小生成树是否唯一"可以理解为"最小生成树和次小生成树是否相等" 求次小生成树的步骤如下 1)先求出最小生成树T,在prim的同时,用一个矩阵maxx[u][v]记录在树中连接u-v的路径中权值最大的边. 2)枚举所有不在T中的边map[u][v],加入边u-v,删除权值为maxx[u][v]的边; 3)找到MST-maxx[u][v]

次短路和次小生成树、

转载:传送门 次短路径与次小生成树问题的简单解法 [次短路径] 次短路径可以看作是k短路径问题的一种特殊情况,求k短路径有Yen算法等较为复杂的方法,对于次短路径,可以有更为简易的方法.下面介绍一种求两个顶点之间次短路径的解法. 我们要对一个有向赋权图(无向图每条边可以看作两条相反的有向边)的顶点S到T之间求次短路径,首先应求出S的单源最短路径.遍历有向图,标记出可以在最短路径上的边,加入集合K.然后枚举删除集合K中每条边,求从S到T的最短路径,记录每次求出的路径长度值,其最小值就是次短路径的长

[kuangbin带你飞]专题八 生成树 - 次小生成树部分

百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么尝试加入它 然后为了不成环 要在环中去除一条边 为了达到"次小"的效果 减去最长的 即F[i][k] 求一下此时的数值 不断更新次小值 2 kru 记录下被加入到最小生成树中的线段 然后进行n-1次枚举 每次都跳过一条被记录的边 求一次kru 得到的值为-1或者一个可能成为次小的值 不断更

次小生成树的两种算法

一."换边"算法 用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就是次小的生成树.可以证明:最小生成树与次小生成树之间仅有一条边不同. 这样相当于运行m次Kruskal算法. 复杂度O(m^2) 示例代码: int Kruskal_MinTree() { int u,v; init(); int i,flag,cnt; minedge = 0; flag = cnt = 0; int tmp = 0;

POJ 1679 次小生成树

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

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

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