Fools and Foolproof Roads(并查集+优先队列)

题目链接:传送门

题意描述:

       给你n个城市,m条边,要你建设p条边,使得最后的区域数为q(区域就是块)。如果为不同区域,建边的权值为min(1e9, 两个区域的变数权值加一)。同一区域,权值为1000。问你是否能执行上述操作,使得最终区域数位q。

题意分析:

       因为要用到块,所以先用并查集或强联通分量求出有多少个块,然后判断块的数目t是否小于q,如果小于q,则直接输出NO;否则,就用优先队列建设建设t-q条不同区域的边,因为同一区域内建边权值为1000,而且可以重边,所以是先建设不同区域的边。

然后再建设剩下的边,要注意的是,边不能自环。所以这题就是用并查集+优先队列就可以解决了,还要注意一些细节。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int>P;
const ll inf = 1e9;
int n, m, p, q;
int fa[100005];
struct road{
    ll from, to, value;
}ro[100005];

int found(int x){
    return x == fa[x]? x : fa[x] = found(fa[x]);
}
void unite(int x, int y){
    x = found(x), y = found(y);
    fa[x] = y;
}
vector<int>Q[100005];
vector<int>vis;
priority_queue<P, vector<P>, greater<P> >pri;
ll num[100005];
int main(){
    cin >> n >> m >> p >> q;
    for(int i=0;i<=n;++i) fa[i] = i;
    for(int i=0;i<m;++i){
        scanf("%d %d %d", &ro[i].from, &ro[i].to, &ro[i].value);
        unite(ro[i].from, ro[i].to);
        Q[ro[i].from].push_back(ro[i].to);
        Q[ro[i].to].push_back(ro[i].from);
    }
    for(int i=0;i<m;++i){
        int temp = found(ro[i].from);
 //       if(temp == ro[i].from && !num[temp])
        if(!num[temp]) vis.push_back(temp);
        num[temp] += ro[i].value;
    }
    for(int i=1;i<=n;++i){
        int temp = found(i);
        if(!num[temp]) vis.push_back(temp);
    }
 //   cout << vis.size() << endl;
    for(int i=0;i<vis.size();++i){
        int v = vis[i];
        ll d = min(inf, num[v]);
        pri.push({d, v});
    }
    if(vis.size() < q) cout << "NO" << endl;
    else if(vis.size() == q){
        if(m == 0 && p) cout << "NO" << endl;
        else{
            cout << "YES" << endl;
            P v = pri.top();
            pri.pop();
            while(!v.first && !pri.empty()){
                v = pri.top();
                pri.pop();
            }
            for(int i=0;i<p;++i) printf("%d %d\n", v.second, Q[v.second][0]);
        }
    }
    else{
        int d = vis.size()-q;
        if(d > p) cout << "NO" << endl;
        else{
            cout << "YES" << endl;
            for(int i=0;i<d;++i){
                P u = pri.top(); pri.pop();
                P v = pri.top(); pri.pop();
                printf("%d %d\n", u.second, v.second);
       //         printf("%lld %lld\n", u.first, v.first);
                Q[u.second].push_back(v.second);
                ll dd = min(inf, (ll)(2ll*(u.first+v.first)+1));
        //        cout << dd << endl;
                pri.push({dd, u.second});
            }
            P v = pri.top();
            pri.pop();
            while(!v.first && !pri.empty()){
                v = pri.top();
                pri.pop();
            }
            for(int i=d;i<p;++i){
                printf("%d %d\n", v.second, Q[v.second][0]);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41100093/article/details/87547660
今日推荐