lightoj 1123 增量最小生成树
题意:有n个点(1<=n<=200),最多有m( 1<=m<=6000) 条边,依次给出每一条边,要求求每次给出的边组成的图中最小生成树的值是多少。如果给出的边还不足以连接n个点组成树,输出-1;
分析:
直接模拟肯定超时,已经预料到了,还是交了一发T表示尊重。。。=v=。
接下来想到并查集的特点,如果倒过来做的话,反而更加复杂,因为从并查集里删去一条边简直噩梦。
可以发现,如果有一棵n节点的生成树了,这时候再加入一条边,必定能形成环,那么我们的任务就变成了,如何删去这个环中最大的权值边。
按照生成树的特点,按边排序后,小的权值是被优先选择的,所以当后面判断到两个点已经在联通分量中时,这条边就是我们要删去的边。
删边技巧,由于我们还是每次都要排序的(并没有使用数据结构维护边集),所以假设我们的边存在 a[0] ~ a[n - 1] 中,其中a[k] 是我们要删去的边。
那么我们就 a[k] = a[n - 1] ; n-- ;
这样,反正我们下次进行MST的时候还是要sort的,所以数组中的大小位置是无所谓的。
因为到后面足够多的边的时候,总能产生生成树,产生了生成树之后,边集的大小就不会变了(每次都一定加入一条边,并删去一条边),所以复杂度不会很高。
教训:
然而即使知道了这些我还是T了,后来检查许久,发现是pair的锅,原本用来存储边的pair是这样的
pair<int,pair<int,int> >road[MAXN];
改成结构体node
struct node{
int w , a , b ;
}road[MAXN];
以后,就A掉了!
pair真是慢.........
1 /* When all else is lost the future still remains. */
2 /* You can be the greatest */
3 #define rep(X,Y,Z) for(int X=(Y);X<(Z);X++)
4 #define drep(X,Y,Z) for(int X=(Y);X>=(Z);X--)
5 #define fi first
6 #define se second
7 #define mk(X,Y) make_pair((X),(Y))
8 //head
9 #include <iostream>
10 #include <stdio.h>
11 #include <queue>
12 #include <algorithm>
13 #include <string>
14 #include <map>
15 using namespace std;
16 #define MAXN 210
17 #define MAXM 6010
18 //pair<int,pair<int,int> > road[MAXM];
19 struct node{
20 int w , a , b;
21 }road[MAXM];
22 int rp[MAXN];
23 int cnt;
24 int N;
25 int f(int x){return rp[x] = (rp[x] == x) ? x : f(rp[x]);}
26 void init(int n){
27 rep(i,1,n+1) rp[i] = i;
28 }
29 bool cmp(node A , node B){
30 return A.w < B.w;
31 }
32 int mst(){
33 int ans = 0;
34 sort(road,road+N,cmp);
35 int pos = -1;
36 rep(i,0,N){
37 int val = road[i].w;
38 int a = f(road[i].a);
39 int b = f(road[i].b);
40 if(a == b){pos = i; continue;}
41 rp[a] = rp[b] = min(a,b);
42 ans += val;
43 cnt--;
44 }
45 if(pos != -1) road[pos] = road[--N];
46 return cnt == 1 ? ans : -1;
47 }
48 int main(){
49 int T;
50 scanf("%d",&T);
51 rep(ca,1,T+1){
52 N = 0;
53 printf("Case %d:\n",ca);
54 int n , m;
55 scanf("%d %d",&n,&m);
56 rep(i,0,m){
57 int a , b , w;
58 scanf("%d %d %d",&road[N].a,&road[N].b,&road[N].w);
59 N++;
60 cnt = n;
61 init(n);
62 printf("%d\n",mst());
63 }
64 }
65 return 0;
66
67 }