AtCoder Petrozavodsk Contest 001 D - Forest 连通块+并查集+贪心
Posted ProLightsfxjh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Petrozavodsk Contest 001 D - Forest 连通块+并查集+贪心相关的知识,希望对你有一定的参考价值。
D - Forest
Time limit : 2sec / Memory limit : 256MB
Score : 600 points
Problem Statement
You are given a forest with N vertices and M edges. The vertices are numbered 0 through N−1. The edges are given in the format (xi,yi), which means that Vertexxi and yi are connected by an edge.
Each vertex i has a value ai. You want to add edges in the given forest so that the forest becomes connected. To add an edge, you choose two different vertices iand j, then span an edge between i and j. This operation costs ai+aj dollars, and afterward neither Vertex i nor j can be selected again.
Find the minimum total cost required to make the forest connected, or print Impossible
if it is impossible.
Constraints
- 1≤N≤100,000
- 0≤M≤N−1
- 1≤ai≤109
- 0≤xi,yi≤N−1
- The given graph is a forest.
- All input values are integers.
Input
Input is given from Standard Input in the following format:
N M a0 a1 .. aN−1 x1 y1 x2 y2 : xM yM
Output
Print the minimum total cost required to make the forest connected, or print Impossible
if it is impossible.
Sample Input 1
Copy7 5 1 2 3 4 5 6 7 3 0 4 0 1 2 1 3 5 6
Sample Output 1
Copy7
If we connect vertices 0 and 5, the graph becomes connected, for the cost of 1+6=7 dollars.
Sample Input 2
Copy5 0 3 1 4 1 5
Sample Output 2
CopyImpossible
We can't make the graph connected.
Sample Input 3
Copy1 0 5
Sample Output 3
Copy0
The graph is already connected, so we do not need to add any edges.
Source
AtCoder Petrozavodsk Contest 001My Solution
题意:给出一个由n个点m条边构成的森林,每个点有个权值val[i],额外加一条边(u,v)的花费是val[u] + val[v],且u、v只能被用到一次,添加一些边使得图连通,求最小花费。连通块+并查集+贪心
可以先用并查集跑出连通块的个数为x,则需要添加的边的数量为x-1条,需要使用的点的个数为2*(x-1),所以只要n>=2*(x-1)则必定有解。所以我们只要贪心的选出这2*(x-1)个点即可,故先在每个连通块选择一个权值最小的点,这样可以保证每个连通块都会有点和其它的连通块相连,然后剩余的2*(x-1) - x个点可以随便选,所以只要把没有用过的点排个序,选择最小的2*(x-1) - x个点即可。这里不要求具体的边,所以只要知道要用的点的集合即可不需要构造出边,故只要把这2*(x-1) - x个选出的点的权值求和即可。
时间复杂度 O(nlogn)
空间复杂度 O(n)
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> ii;
const int MAXN = 1e5 + 8;
priority_queue<ii, vector<ii>, greater<ii>> pq[MAXN];
int val[MAXN];
int fa[MAXN], _rank[MAXN];
inline void init(int n)
for(int i = 0; i <= n; i++)
fa[i] = i;
_rank[i] = 0;
inline int _find(int u)
return fa[u] = fa[u] == u ? u : _find(fa[u]);
inline void _merge(int u, int v)
int x = _find(u), y = _find(v);
if(x == y) return;
if(_rank[x] < _rank[y])
fa[x] = y;
else
fa[y] = x;
if(_rank[x] == _rank[y]) _rank[x]++;
vector<ii> vec;
int main()
#ifdef LOCAL
freopen("d.txt", "r", stdin);
//freopen("d.out", "w", stdout);
int T = 1;
while(T--)
#endif // LOCAL
ios::sync_with_stdio(false); cin.tie(0);
int n, m, i, u, v, findu, findv;
LL ans = 0;
cin >> n >> m;
init(n);
for(i = 0; i < n; i++)
cin >> val[i];
for(i = 0; i < m; i++)
cin >> u >> v;
findu = _find(u), findv = _find(v);
if(findu != findv)
_merge(findu, findv);
for(i = 0; i < n; i++)
pq[_find(i)].push(ii(val[i], i));
for(i = 0; i < n; i++)
if(!pq[i].empty())
vec.push_back(pq[i].top());
val[pq[i].top().second] = 2e9;
ans += pq[i].top().first;
//cout << vec.size() << endl;
if(vec.size() == 1)
cout << 0 << endl;
else if(n < (vec.size()-1) * 2) cout << "Impossible" << endl;
else
sort(val, val + n);
n = (vec.size()-1) * 2 - vec.size();
for(i = 0; i < n; i++)
ans += val[i];
cout << ans << endl;
#ifdef LOCAL
cout << endl;
#endif // LOCAL
return 0;
Thank you!
------from ProLights
以上是关于AtCoder Petrozavodsk Contest 001 D - Forest 连通块+并查集+贪心的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Petrozavodsk Contest 001 C - Vacant Seat 交互题带分类讨论的二分
2020 Petrozavodsk Winter Camp, Jagiellonian U Contest 部分题解
2020 Petrozavodsk Winter Camp, Jagiellonian U Contest 部分题解
Petrozavodsk Winter-2019. Yandex Cup 2019.