2018年ACM俱乐部个人训练赛第十六场 问题A.森林扩张

问题 A: 森林扩张

时间限制: 1 Sec  内存限制: 256 MB

题目描述

小L走进了一片森林。这片森林由n个点和m条边组成,每个点都有一个大小ai。小L不小心在森林里迷路了,于是TA决定给森林添上几条边,把整片森林连成一棵树,就能走出去了,在点i与点j间连一条边需要花费ai+aj的代价。此外,小L还发现每个点上最多只能添一条边。小L想知道能不能走出森林,如果能的话,最小代价是多少。

输入

第一行两个整数n和m,表示森林的点数与边数。接下来一行,n个以空格分隔的整数,表示每个点的大小。接下来m行,每行两个正整数,描述森林的一条边。保证给出的图是一片森林。

输出

假如不能把森林变成一棵树,输出−1,否则输出最小代价。

样例输入

5 2
1 2 5 3 4
1 3

2 4

样例输出

10

提示

在点1与点2间加入一条边,点4与点5间加入一条边,总代价是1 + 2 + 3 + 4 = 10。
对于30%的数据,所有点的点权都相同;
对于100%的数据,0 ≤ m < n ≤ 105, 0 ≤ ai ≤ 109,保证给出的图是一片森林(可能是一棵完整的树)。




分析:

每个连通分量内的点找一个最小的  然后再在所有点里找剩下需要的点  一共需要 (连通分量个数-1)*2个点  点不够输出-1






扫描二维码关注公众号,回复: 2449182 查看本文章

AC代码:

#include <bits/stdc++.h>  
#define mset(a,x) memset(a,x,sizeof(a))  
typedef long long ll;  
using namespace std;  
ll a[1000005];
int pre[1000005];
struct node{
    int Index;
    ll min;
    int ti;
}temp[1000005];
int find(int x){
    int r=x;
    while (pre[r]!=r){
        r=pre[r];
    }
    int i=x;
    int temp;
    while (i!=r){
        temp=pre[i];
        pre[i]=r;
        i=temp;
    }
    return r;
}
void join(int x,int y){
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy){
        pre[fx]=fy;
    }
}
void init(){for(int i=0;i<=1000001;i++) pre[i]=i;}
int main (){
    int n,m;
    while (scanf ("%d%d",&n,&m)!=EOF){
        init();
        for (int i=1;i<=n;i++) scanf ("%lld",&a[i]);
        int u,v;
        for (int i=0;i<m;i++){
            scanf ("%d%d",&u,&v);
            join(u,v);
        }
        for (int i=0;i<=n;i++) temp[i].min=0x3f3f3f3f;
        int cnt=0;
        for (int i=1;i<=n;i++)
            if (find(i)==i) temp[cnt++].Index=i;
        if(cnt==1) {
            printf("0\n");continue;
        }
        for (int i=1;i<=n;i++){
            int tt=find(i);
            int l=0,r=cnt-1;
            while (l<=r){
                int mid=(l+r)/2;
                if (temp[mid].Index==tt){
                    if(temp[mid].min>a[i]){
                        temp[mid].min=a[i];
                        temp[mid].ti=i;
                    } 
                    break;
                }
                else if (temp[mid].Index>tt) r=mid-1;
                else l=mid+1;
            }
        }
        ll sum=0;
        for (int i=0;i<cnt;i++) sum+=temp[i].min,a[temp[i].ti]=0x3f3f3f3f;
        sort(a+1,a+1+n);
        int flag=0;
        for (int i=1;i<=cnt-2;i++){
            if (a[i]!=0x3f3f3f3f) sum+=a[i];
            else{
                flag=1;break;
            }
        }
        if (flag) printf ("-1\n");
        else printf ("%lld\n",sum);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/mm__1997/article/details/79419078