题意:
给定n和m,表示二维平面上有n个点,m堵墙,
给出每个点在二维平面上的坐标,
第i堵墙连接(u,v),被墙堵住的地方不能走.
每堵墙拆除都有一个代价,
现在问最少拆除多少堵墙,
能使得每个点都能到达其他点(图连通)
在最少拆除的前提下代价尽可能少,
输出最少拆除和最小代价.
数据范围:n<=1e5,m<=2e5,保证墙不存在自环和重边
解法:
这题的坐标没有用(因为是二维无限大平面)
要使得每个点都能到达其他点,
那么其实就是要让图中的墙不存在环,
反过来想,考虑哪些墙是可以保留的,
首先要保证保留下来的墙不能形成环,
同时需要满足尽量保留更多的墙,保留的墙的总代价尽可能大.
无环图要想到树和森林,因此这题就是求一个最大生成树,
最大生成树就是能保留下来的最多的墙,同时代价尽可能大.
因此这题跑一波最大生成树,记录一下最大生成树边权和,以及边得数量就行了.
需要注意的点:
题目给的图可能不是连通的,因此跑kruskal的结果的可能是森林,
这时候边的总数不是n-1,所以要开一个变量记录一下选出了多少个边.
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e6+5;
struct Node{
int a,b,c;
}e[maxm];
int pre[maxm];
int n,m;
int ffind(int x){
return pre[x]==x?x:pre[x]=ffind(pre[x]);
}
bool cmp(Node a,Node b){
return a.c>b.c;
}
signed main(){
ios::sync_with_stdio(0);
while(cin>>n>>m){
for(int i=1;i<=n;i++)pre[i]=i;
for(int i=1;i<=n;i++){
int x,y;cin>>x>>y;
}
int tot=0;
for(int i=1;i<=m;i++){
int a,b,c;cin>>a>>b>>c;
e[i]={a,b,c};
tot+=c;
}
sort(e+1,e+1+m,cmp);
int cnt=0;
int sum=0;
for(int i=1;i<=m;i++){
int x=ffind(e[i].a);
int y=ffind(e[i].b);
if(x!=y){
pre[x]=y;
sum+=e[i].c;
cnt++;
if(cnt==n-1)break;
}
}
cout<<m-cnt<<' '<<tot-sum<<endl;
}
return 0;
}