题目链接:传送门
题意描述:
给你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;
}