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 Vertex xi 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 i and 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
Copy
7 5
1 2 3 4 5 6 7
3 0
4 0
1 2
1 3
5 6
Sample Output 1
Copy
7
If we connect vertices 0 and 5, the graph becomes connected, for the cost of 1+6=7 dollars.
Sample Input 2
Copy
5 0
3 1 4 1 5
Sample Output 2
Copy
Impossible
We can’t make the graph connected.
Sample Input 3
Copy
1 0
5
Sample Output 3
Copy
0
The graph is already connected, so we do not need to add any edges.
Submit
题目链接: https://apc001.contest.atcoder.jp/tasks/apc001_d
题意:就是给你 n(编号 0 ~ n - 1) 个点,m 条边以及每个点的点权。
问:要使所有点形成一个联通块最少的花费?(点 i 和 点 j 相连 花费增加 cost[i] + cost[j],且每个点只能选一次)
一开始给的图是森林。
数据范围:
解题思路:
错误总结:我一开始写采用的方法是:依次把每个部分合并,一边合并一边用优先队列维护每部分的最小点权值。但这样写是错的,比如以下样例:
若按照我原先的方法来选的话(先忽略点权),先是选 0号点 和 1号点 合并,之后 0号点 和 1号点 都不能再次被选了,就会输出 Impossible。但其实只要 0号点 与 2号点 连,1 号点 与 3号点 连就可以了。
解题代码:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 5;
vector<int> G[maxn];
int low[maxn],dfn[maxn],in[maxn];
bool vis[maxn];
stack<int> st;
LL cost[maxn],p[maxn],sum = 0,num = 0;
priority_queuevector, greater > que;
int n,m,ind,cnt;
void dfs(int x){//缩点
low[x] = dfn[x] = ++ind;
st.push(x),vis[x] = 1;
for(int i = 0;i < G[x].size();i++){
int v = G[x][i];
if(!dfn[v]){
dfs(v);
low[x] = min(low[x],low[v]);
}
else if(vis[v]){
low[x] = min(low[x],dfn[v]);
}
}
if(low[x] == dfn[x]){
int all = 0;
cnt++;
bool flag = false;
while(!st.empty()){
int tot = st.top();
st.pop();
vis[tot] = 0;
in[tot] = 0;
in[tot] = cnt;
p[++all] = cost[tot];
flag = true;
if(tot == x) break;
}
if(flag){
sort(p + 1,p + 1 + all);
sum += p[1];
num++;
for(int i = 2;i <= all;i++) que.push(p[i]);
}
}
}
int main(){
scanf("%d %d",&n,&m);
for(int i = 0;i < n;i++) scanf("%lld",&cost[i]);
for(int i = 1;i <= m;i++){
int x,y;
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
if(n < 2 * (n - m - 1)){
printf("Impossible\n");
return 0;
}
else if(n == m + 1){
printf("0\n");
return 0;
}
for(int i = 0;i < n;i++){
if(!dfn[i]) dfs(i);
}
while(num < 2 * (n - m - 1)){
if(!que.empty()){
LL ans = que.top();
que.pop();
sum += ans;
num++;
}
}
printf("%lld\n",sum);
return 0;
}