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 }

 

posted @ 2016-10-09 21:27  ACMZZ  阅读(701)  评论(1编辑  收藏  举报