【題解】逐個擊破 luogu2700
阿新 • • 發佈:2017-10-30
white cdt ldl 離開 ros print .aspx -h ftw
題目
題目描述:
現在有N個城市,其中K個被敵方軍團占領了,N個城市間有N-1條公路相連,破壞其中某條公路的代價是已知的。
現在,告訴你K個敵方軍團所在的城市,以及所有公路破壞的代價,請你算出花費最少的代價將這K個地方軍團互相隔離開,以便第二步逐個擊破敵人。
輸入格式
第一行包含兩個正整數n和k。
第二行包含k個整數,表示哪個城市別敵軍占領。
接下來n-1行,每行包含三個正整數a,b,c,表示從a城市到b城市有一條公路,以及破壞的代價c。城市的編號從0開始。
輸出格式
輸出一行一個整數,表示最少花費的代價。
輸入輸出樣例
輸入
5 3 1 2 4 1 0 4 1 3 8 2 1 1 2 4 3
輸出
4
思路
-
貪心一下,使得兩個被占領的城市不連通,並不需要將中間的普通道路全部拆光,只要選取一些和占領點相連的邊。
-
可以想到,如果一條邊和另一條邊相連了,那麽可以將兩條邊視為一條邊,同理推廣到所有的邊上,引出了並查集思想,當然也可以用 kruskal 來理解。
-
那麽對於一條邊所處的並查集,如果裏面已經與一個聚集地相連,那麽這個並查集一
定不能和另外一個包含與另外的聚集地相連的路徑的並查集合並,對於合法的路徑,每次加入的時候我們統計它的長度,因為路徑合法,所以不是必須拆掉的路。 -
最後用總長度減去這些長度就可以得到拆路的最少代價。
-
先將邊排序,保證選擇到必須拆的道路時一定是花費最少的
代碼
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,m;
long long ans;
int vis[100010],fa[100010];
struct arr{
int u,v,w;
}e[100010];
inline int read(){
int x=0,w=1;char ch=0 ;
while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
if(ch==‘0‘) w=-1,ch=getchar();
while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
int gf(int x){ return x==fa[x]?x:fa[x]=gf(fa[x]);}
inline int cmp(arr a,arr b){ return a.w>b.w;}
int main(){
//freopen("shiitake.in","r",stdin);
//freopen("shiitake.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;i++){
int x=read();vis[x]=1;
}
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read(); e[i].u=u;e[i].v=v;e[i].w=w; ans+=w;
}
sort(e+1,e+n,cmp);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<n;i++){
int f1=gf(e[i].u);
int f2=gf(e[i].v);
if(!(vis[f1]&&vis[f2])){
fa[f2]=f1;
vis[f1]=(vis[f1]||vis[f2]);
ans-=e[i].w;
}
}
printf("%lld\n",ans);
}
?
【題解】逐個擊破 luogu2700