1380: 森林扩张
时间限制: 1 Sec 内存限制: 256 MB提交: 130 解决: 23
[ 提交][ 状态][ 讨论版]
题目描述
小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,保证给出的图是一片森林(可能是一棵完整的树)。
来源
【题意】
中文题,好理解
【思路】
每个点只能用一次;
利用并查集把有关系的边建立到一个关系中,也可以利用DFS,道理是一样的;
然两个Set容器, 一个存放集合,维护,另有一个不断更新集合,然后把除去最小的存到第一个set中;最小的是需要建的边,把值加上;
当第一个set =0 时 说明 无法建边 -1
最后第一个Set就是 应该再次计算的值, W=ai+aj;
【感悟】
思路是对的,但是一直WA, 又没有数据, 气得我 自己写了个随机生产数据的函数, 然后用对拍;
没想到 真的就对拍出一组数据 过不了;改啊改;
【代码实现】
具体看代码;
#include <iostream>
#include <bits/stdc++.h>
#include <stdio.h>
typedef long long ll;
#define mem(a,b) memset(a,b,sizeof(a))
const ll INF=0x3f3f3f3f;
const int MAXN=1e6+5;
using namespace std;
int n,m;
ll a[MAXN];
ll pre[MAXN<<1];
ll vis[MAXN];
void init()
{
mem(vis,0);
for(ll i=1;i<=n;i++)
pre[i]=i;
}
int find(int x)
{
return pre[x]== x? x: (pre[x]=find(pre[x]));
}
void join(ll x,ll y)
{
ll fx=find(x),fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
multiset<ll>S1,S2;
multiset<ll>::iterator it,ano;
vector<ll> V[MAXN];
int main()
{
S1.clear();
S2.clear();
cin>>n>>m;
init();
for(int i=0;i<=n;i++) V[i].clear();
for(int i=1;i<=n;i++)
cin>>a[i];
ll x,y;
while(m--)
{
cin>>x>>y;
join(x,y);
}
ll ans=0;
ll cot=0;
int flag=0;
for(int i=1;i<=n;i++)
{
V[find(i)].push_back(a[i]);
if(pre[i]==i)
cot++;
}
if(cot==1)
{
cout<<0<<endl;
return 0;
}
S1.clear();
for(int i=1;i<=n;i++)
{
if(V[i].size()>0&&!vis[i])
{
vis[i]=1;
S2.clear();
for(int j=0;j<V[i].size();j++)
{
S2.insert(V[i][j]);
}
ans+= (*S2.begin());
it=S2.begin();
S2.erase(it);
for( it=S2.begin();it!=S2.end();it++)
S1.insert(*it);
S2.clear();
}
}
//cout<<ans<<endl;
if(S1.size()<cot-2)
{
//cout<<"Sfgafas"<<endl;
cout<<-1<<endl;
return 0;
}
int i;
for( it=S1.begin(),i=0;i<cot-2;it++,i++)
{
//cout<<(*it)<<" "<<endl;
ans+= (*it);
}
cout<<ans<<endl;
return 0;
}
123