zoukankan      html  css  js  c++  java
  • 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:
    ",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
    ",mst());
    63         }
    64     }
    65     return 0;
    66 
    67 }
  • 相关阅读:
    1014. 福尔摩斯的约会
    1009. 说反话
    1002. 写出这个数
    1031. 查验身份证
    1021. 个位数统计
    1006. 换个格式输出整数
    1058. A+B in Hogwarts
    1027. Colors in Mars
    1019. General Palindromic Number
    Windows 新装进阶操作指南
  • 原文地址:https://www.cnblogs.com/ticsmtc/p/5943869.html
Copyright © 2011-2022 走看看