UVA10462Is There A Second Way Left? —— 次小生成樹 kruskal算法
題目鏈接:https://vjudge.net/problem/UVA-10462
Nasa, being the most talented programmer of his time, can’t think things to be so simple. Recently all his neighbors have decided to connect themselves over a network (actually all of them want to share a broadband internet connection :-)). But he wants to minimize the total cost of cable required as he is a bit fastidious about the expenditure of the project. For some unknown reasons, he also wants a second way left. I mean, he wants to know the second best cost (if there is any which may be same as the best cost) for the project. I am sure, he is capable of solving the problem. But he is very busy with his private affairs(?) and he will remain so. So, it is your turn to prove yourself a good programmer. Take the challenge (if you are brave enough)...
Input
Input starts with an integer t ≤ 1000 which denotes the number of test cases to handle. Then follows t datasets where every dataset starts with a pair of integers v (1 ≤ v ≤ 100) and e (0 ≤ e ≤ 200). v denotes the number of neighbors and e denotes the number of allowed direct connections among them. The following e lines contain the description of the allowed direct connections where each line is of the form ‘start end cost’, where start and end are the two ends of the connection and cost is the cost for the connection. All connections are bi-directional and there may be multiple connections between two ends.
Output
There may be three cases in the output 1. No way to complete the task, 2. There is only one way to complete the task, 3. There are more than one way. Output ‘No way’ for the first case, ‘No second way’ for the second case and an integer c for the third case where c is the second best cost. Output for a case should start in a new line.
Sample Input 4 5 4 1 2 5 3 2 5 4 2 5 5 4 5 5 3 1 2 5 3 2 5 5 4 5 5 5 1 2 5 3 2 5 4 2 5 5 4 5 4 5 6 1 0
Sample Output
Case #1 : No second way
Case #2 : No way
Case #3 : 21
Case #4 : No second way
題解:
1.求次小生成樹。但是題目要求可以有重邊,而prim算法處理的是點與點的關系,不能(至少很難)處理有重邊的圖。
2.求最小生成樹,除了prim算法之外,還有kruskal算法,且因為它是直接依據邊來進行操作的,所以就能很好地處理重邊了。
3.步驟:先用kruskal算法求出最小生成樹,同時記錄下最小生成樹邊。然後枚舉刪除每一條最小生成樹邊,再去求最小生成樹,最終即可得到次小生成樹。
4.復雜度分析:O(n*m),計算次數為2e4,再乘上case數,計算次數為2e7,所以可行。
代碼如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 typedef long long LL; 7 const double EPS = 1e-6; 8 const int INF = 2e9; 9 const LL LNF = 9e18; 10 const int MOD = 1e9+7; 11 const int MAXN = 1e2+10; 12 13 struct Edge 14 { 15 int u, v, w; 16 bool operator<(const Edge &a)const{ 17 return w<a.w; 18 } 19 }edge[MAXN<<1]; 20 int fa[MAXN], used[MAXN]; 21 22 int find(int x) { return fa[x]==-1?x:x=find(fa[x]); } 23 24 int kruskal(int n, int m, int pointed) 25 { 26 int cnt = 0, sum = 0; 27 memset(fa, -1, sizeof(fa)); 28 for(int i = 1; i<=m; i++) 29 { 30 if(i==pointed) continue; //如果是那條被指定刪除的最小生成樹邊,則跳過 31 32 int u = find(edge[i].u); 33 int v = find(edge[i].v); 34 if(u!=v) 35 { 36 fa[u] = v; 37 sum += edge[i].w; 38 ++cnt; //錯誤:不能放到下一句裏面, 即used[++cnt]=i, 因為這條語句必須要執行!!! 39 if(pointed==-1) used[cnt] = i; //如果求最小生成樹,則把編號為i的邊加入生成樹中 40 if(cnt==n-1) return sum; //合並了n-1次,已成樹,可直接返回 41 } 42 } 43 return cnt<(n-1)?INF:sum; //當合並次數小於n-1時,不能構成樹 44 } 45 46 int main() 47 { 48 int T, n, m; 49 scanf("%d", &T); 50 for(int kase = 1; kase<=T; kase++) 51 { 52 scanf("%d%d",&n,&m); 53 for(int i = 1; i<=m; i++) 54 scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w); 55 56 sort(edge+1, edge+1+m); 57 58 int t1 = INF, t2 = INF; 59 t1 = kruskal(n, m, -1); //求最小生成樹 60 for(int i = 1; i<=n-1; i++) //枚舉刪除每一條最小生成樹邊邊,求次小生成樹 61 { 62 int tmp = kruskal(n, m, used[i]); 63 t2 = min(t2, tmp); 64 } 65 66 if(t1==INF) //原圖不連通,既沒有最小生成樹 67 printf("Case #%d : No way\n", kase); 68 else if(t2==INF) //沒有次小生成樹 69 printf("Case #%d : No second way\n", kase); 70 else 71 printf("Case #%d : %d\n", kase, t2); 72 } 73 }View Code
UVA10462Is There A Second Way Left? —— 次小生成樹 kruskal算法