【LightOJ - 1123】Trail Maintenance(在线维护最小生成树,删边思维)
題干:
Tigers in the Sunderbans wish to travel freely among the?N?fields (numbered from?1?to?N), even though they are separated by trees. The tigers wish to maintain trails between pairs of fields so that they can travel from any field to any other field using the maintained trails. Tigers may travel along a maintained trail in either direction.
The tigers do not build trails. Instead, they maintain deer trails that they have discovered. On any week, they can choose to maintain any or all of the deer animal trails they know about. Always curious, the tigers discover one new deer trail at the beginning of each week. They must then decide the set of trails to maintain for that week so that they can travel from any field to any other field. Tigers can only use trails which they are currently maintaining.
The tigers always want to minimize the total length of trail they must maintain. The tigers can choose to maintain any subset of the deer trails they know about, regardless of which trails were maintained the previous week. Deer trails (even when maintained) are never straight. Two trails that connect the same two fields might have different lengths. While two trails might cross, tigers are so focused; they refuse to switch trails except when they are in a field. At the beginning of each week, the tigers will describe the deer trail they discovered. Your program must then output the minimum total length of trail the tigers must maintain that week so that they can travel from any field to any other field, if there is such a set of trails.
Input
Input starts with an integer?T (≤ 25), denoting the number of test cases.
Each case starts with two integers?N (1 ≤ N ≤ 200)?and?W.?W?is the number of weeks the program will cover?(1 ≤ W ≤ 6000).
Each of the next?W?lines will contain three integers describing the trail the tigers found that week. The first two numbers denote the end points (filed numbers) and the third number denotes the length of the trail?(1 to 10000). No trail has the same field as both of its end points.
Output
For each case, print the case number in a line. Then for every week, output a single line with the minimum total length of trail the tigers must maintain so that they can travel from any field to any other field. If no set of trails allows the tigers to travel from any field to any other field, output?"-1".
Sample Input
1
4 6
1 2 10
1 3 8
3 2 3
1 4 3
1 3 6
2 1 2
Sample Output
Case 1:
-1
-1
-1
14
12
8
題目大意:
? n個點,m個邊順序添加,每次添加,要求在線輸出MST的權值,如果湊不出MST就輸出-1。
解題報告:
? 直接暴力肯定會超時。
? 考慮到n只有200:因為最差情況:大于n條邊的時候,肯定會生成一個環,那么最終生成環的這一條邊,肯定是我們最后遍歷到的,而恰好肯定是環內權值最大的(因為按邊權排序了之后再遍歷的。),所以這一條邊可以直接扔掉(簡化操作就是記錄一下這個邊的位置,然后遍歷結束后把最后一條邊直接賦值過來。)
? 下面給出簡要證明:為什么這一條邊e一定不會要,也就是,不管后面的邊如何添加的,這一條邊一定沒用了(也就是一定不會是MST中的邊):因為每次加邊操作都是只加一條,所以最多替換一條邊,考慮每次替換邊,都是去掉一條邊w1,換上一條邊w2,那么這個替換執行 當且僅當w1>w2,也就是新邊的權值肯定要更小,我們才考慮替換他。由上一段的分析得知,這條邊e的權值we>w1,所以這一條邊we>w2,所以肯定這條邊沒用了。因為他只要是棵樹,我們不需要看邊選的是啥,因為可以確定的是,樹上的點一定就是那一些,所以具體哪些邊沒影響。至此,我們可以放心大膽的刪掉這條邊了。
? 這次是體會到了常數的可怕。。。把自定義比較函數放在結構體內部確實是快(160ms級別和240ms級別的區別。)另外getf也是這樣,uv直接變成祖先節點才能沖進200ms,不然就是200多ms。不過如果不卡并查集的話問題就不大。
? ?另外對于這題,不能加cnt==n-1則break。因為可能需要刪除的邊在后面。總之這一點可以被卡。所以要注意。不過其實最多穩定在200條邊,所以加不加這個優化影響不大。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e5 + 5; int f[222]; struct Edge {int u,v,w;bool operator<(const Edge b) const {return w < b.w;} } e[MAX]; int tot,n,m; int getf(int v) {return f[v] == v ? v : f[v] = getf(f[v]); } void init() {for(int i = 1; i<=n; i++) f[i] = i; } int klu() {sort(e+1,e+tot+1);int cnt = 0,pos=-1,res = 0;for(int i = 1; i<=tot; i++) {int u = getf(e[i].u),v = getf(e[i].v);if(u==v) pos = i;else {f[v]=u;res += e[i].w;cnt++;} // if(cnt == n-1) break; } if(pos != -1) {e[pos] = e[tot];tot--;}if(cnt == n-1) return res;else return -1; } int main() {int t,iCase = 0;scanf("%d",&t);while(t--) {printf("Case %d:\n",++iCase);tot=0;scanf("%d%d",&n,&m);for(int a,b,c,i = 1; i<=m; i++) {scanf("%d%d%d",&a,&b,&c);e[++tot].u = a;e[tot].v = b;e[tot].w = c;init();printf("%d\n",klu());}}return 0 ; }換了一種優化反而更慢(161ms)注意這樣寫的話要提前賦值tot給tott,并且遍歷邊的時候還是遍歷到tott。因為你后面的那些邊雖然可能要刪除,但是前提是在你找到MST的時候,你在線就tot--了,可能人家本來就是第tot條邊湊出MST,但是你這樣操作就輸出-1了。
總結一下這樣慢的原因,其實沒必要加那個cnt==n-1就break。因為本來邊就不多,動態穩定在n-1附近,,所以沒必要,,因為反而增加了很多次if判斷,所以耗時了。
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e5 + 5; int f[222]; struct Edge {int u,v,w;bool operator<(const Edge b) const {return w < b.w;} } e[MAX]; int tot,n,m; int getf(int v) {return f[v] == v ? v : f[v] = getf(f[v]); } void init() {for(int i = 1; i<=n; i++) f[i] = i; } int klu() {sort(e+1,e+tot+1);int cnt = 0,pos=-1,res = 0,tott=tot;for(int i = 1; i<=tott; i++) {int u = getf(e[i].u),v = getf(e[i].v);if(u==v) {e[i] = e[tot];tot--;}else {f[v]=u;res += e[i].w;cnt++;}if(cnt == n-1) {tot=i;break; }} // if(pos != -1) { // e[pos] = e[tot]; // tot--; // }if(cnt == n-1) return res;else return -1; } int main() {int t,iCase = 0;scanf("%d",&t);while(t--) {printf("Case %d:\n",++iCase);tot=0;scanf("%d%d",&n,&m);for(int a,b,c,i = 1; i<=m; i++) {scanf("%d%d%d",&a,&b,&c);e[++tot].u = a;e[tot].v = b;e[tot].w = c;init();printf("%d\n",klu());}}return 0 ; }?
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【LightOJ - 1123】Trail Maintenance(在线维护最小生成树,删边思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 申请信用卡没有工作单位怎么办 四点条件优
- 下一篇: 还剩最后几天,存量房贷将执行新贷款利率,