题目链接: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