2018山东冬令营:森林扩张,UPC(1380)
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
岂曰无衣?与子同袍。王于兴师,修我戈矛。与子同仇!
岂曰无衣?与子同泽。王于兴师,修我矛戟。与子偕作!
岂曰无衣?与子同裳。王于兴师,修我甲兵。与子偕行!