ACM Contest and Blackout UVA - 10600 次小生成树之Prim算法
In order to prepare the “The First National ACM School Contest” (in 20??) the major of the city decided to provide all the schools with a reliable source of power. (The major is really afraid of blackoutsJ). So, in order to do that, power station “Future” and one school (doesn’t matter which one) must be connected; in addition, some schools must be connected as well.
You may assume that a school has a reliable source of power if it’s connected directly to “Future”, or to any other school that has a reliable source of power. You are given the cost of connection between some schools. The major has decided to pick out two the cheapest connection plans – the cost of the connection is equal to the sum of the connections between the schools. Your task is to help the major — find the cost of the two cheapest connection plans.
Input
The Input starts with the number of test cases, T (1 < T < 15) on a line. Then T test cases follow. The first line of every test case contains two numbers, which are separated by a space, N (3 < N < 100) the number of schools in the city, and M the number of possible connections among them. Next M lines contain three numbers Ai , Bi , Ci , where Ci is the cost of the connection (1 < Ci < 300) between schools Ai and Bi . The schools are numbered with integers in the range 1 to N.
Output
For every test case print only one line of output. This line should contain two numbers separated by a single space – the cost of two the cheapest connection plans. Let S1 be the cheapest cost and S2 the next cheapest cost. It’s important, that S1 = S2 if and only if there are two cheapest plans, otherwise S1 < S2. You can assume that it is always possible to find the costs S1 and S2.
Sample Input
2
5 8
1 3 75
3 4 51
2 4 19
3 2 95
2 5 42
5 4 31
1 2 9
3 5 66
9 14
1 2 4
1 8 8
2 8 11
3 2 8
8 9 7
8 7 1
7 9 6
9 3 2
3 4 7
3 6 4
7 6 2
4 6 14
4 5 9
5 6 10
Sample Output
110 121
37 37
题意:有n个学校要通过电线相互连接,给你每个学校之间的电线图,请你给出两套花费最少的连接方案,让第一个是最便宜的成本,第二个是较便宜的成本
思路:保证连接的最小花费,很明显就是最小生成树,题意要的是两个成本,那么另一个应该是次小生成树了,代码没什么难的,直接套模板就行。
代码:
1 #include <cstdio> 2 #include <fstream> 3 #include <algorithm> 4 #include <cmath> 5 #include <deque> 6 #include <vector> 7 #include <queue> 8 #include <string> 9 #include <cstring> 10 #include <map> 11 #include <stack> 12 #include <set> 13 #include <sstream> 14 #include <iostream> 15 #define mod 998244353 16 #define eps 1e-6 17 #define ll long long 18 #define INF 0x3f3f3f3f 19 using namespace std; 20 21 //ma存放两点之间的初始距离 22 int ma[105][105]; 23 //low存放到起点的最小距离, 24 int low[105]; 25 //per存放与当前点连接距离最短的另一个点 26 int per[105]; 27 //bj用于判断该点时候在生成树中,con用于标记在生成树中的边 28 bool bj[105],con[105][105]; 29 //maxn存放两点之间的最大值 30 int maxn[105][105]; 31 int n; 32 //最小生成树算法,u表示树的起点 33 int prim(int u) 34 { 35 for(int i=1;i<=n;i++) 36 { //初始low的距离与per指向的点 37 low[i]=ma[u][i]; 38 per[i]=u; 39 } 40 //初始化标记 41 memset(maxn,0,sizeof(maxn)); 42 memset(bj,0,sizeof(bj)); 43 memset(con,0,sizeof(con)); 44 //起点是树上的第一个点,标记 45 bj[u]=1; 46 //ans保存树的所有权值和 47 int ans=0; 48 //遍历其他n-个点 49 for(int i=1;i<n;i++) 50 { 51 //通过遍历找到距离当前起点的最短的边 52 int mi=INF; 53 int v=-1; 54 for(int j=1;j<=n;j++) 55 { 56 if(!bj[j]&&low[j]<mi) 57 { 58 mi=low[j]; 59 v=j; 60 } 61 } 62 //有最短边后 63 if(v!=-1) 64 { 65 //将这个边的两个点标记 66 con[v][per[v]]=con[per[v]][v]=1; 67 //累加权值 68 ans+=mi; 69 //标记这个点 70 bj[v]=1; 71 //记录这个边的值, 72 maxn[v][per[v]]=maxn[per[v]][v]=mi; 73 //再遍历一遍,以更新数据 74 for(int j=1;j<=n;j++) 75 { 76 //j表示的点再树上,且j不是终点 77 if(bj[j]&&j!=v) 78 { //更新v与其他在树上的点之间的最大权值 79 maxn[j][v]=maxn[v][j]=max(maxn[j][per[v]],maxn[per[v]][v]); 80 } 81 //j表示的点不在树上,且满足更新需要 82 if(!bj[j]&&low[j]>ma[v][j]) 83 { 84 //更新low的距离和per指向的点 85 low[j]=ma[v][j]; 86 per[j]=v; 87 } 88 } 89 } 90 } 91 return ans; 92 } 93 94 //次小生成树算法,s表示最小生成树的权值和 95 int secondprim(int s) 96 { 97 int ans=INF; 98 //遍历所有点与其他点 99 //求最小生成树在外加一条边并且删除环的最大边后的值的最小值 100 for(int i=1;i<n;i++) 101 { 102 for(int j=i+1;j<=n;j++) 103 { 104 //如果这个边不在树上 105 if(!con[i][j]) 106 { //s+ma-maxn表示最小生成树在加上一条外边 107 //并删除外边所在环差外边外的最大值。就是子生成树的权值和 108 ans = min(ans,s+ma[i][j]-maxn[i][j]); 109 } 110 } 111 } 112 return ans; 113 } 114 //初始化地图以保证数据的准确性 115 void build(int s) 116 { 117 for(int i=0;i<=s;i++) 118 { 119 for(int j=0;j<=s;j++) 120 { 121 if(i!=j) 122 { 123 ma[i][j]=INF; 124 } 125 else 126 { 127 ma[i][j]=0; 128 } 129 } 130 } 131 } 132 int main() 133 { 134 int t; 135 scanf("%d",&t); 136 while(t--) 137 { 138 int m; 139 scanf("%d %d",&n,&m); 140 build(n); 141 int a,b,c; 142 for(int i=0;i<m;i++) 143 { 144 scanf("%d %d %d",&a,&b,&c); 145 ma[a][b]=ma[b][a]=c; 146 } 147 int s1=prim(1); 148 int s2=secondprim(s1); 149 printf("%d %d\n",s1,s2); 150 } 151 }