http://acm.hdu.edu.cn/showproblem.php?pid=6763 题目链接
题意
:n 个城市 b条路 每个城市都有灯 每个灯都有亮度 每次从联通的城市里面选择一些亮度一起-1;问要减多少次;
做法:
并查集+sort 先按照亮度排序,把所有点看成孤立的,ans+=当前节点亮度,由于会多加,后面开始减; 然后建图,按照亮度从大到小倒着读 ,每次遍历与当前节点有连边的且访问过的节点 ,如果不在一个集合里面ans-=当前节点亮度(母节点,由于之前算的时候多加了这个节点的亮度,本来可以一起)并加入到一个集合里面去。重复操作。结束
代码
#include<bits/stdc++.h> using namespace std; int f[2000005]; struct st{ long long b,i; }s[100005]; int vis[2000005]; vector<int >g[100005]; int ff(int x){ if(x==f[x]){ return x; } else{ return f[x]=ff(f[x]); } } bool cmp(const st &x,const st &y){ return x.b>y.b; } int main(){ int t; cin>>t; while(t--){ int n,m; cin>>n>>m; long long ans=0; for(int i=1;i<=n;i++){ f[i]=i; vis[i]=0; scanf("%d",&s[i].b); ans+=s[i].b; s[i].i=i; g[i].clear(); } sort(s+1,s+1+n,cmp); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } for(int i=1;i<=n;i++){ for(auto v:g[s[i].i]){ if(vis[v]){ int w=ff(v); if(w!=ff(s[i].i)){ f[w]=ff(s[i].i); ans-=s[i].b; } } } vis[s[i].i]=1; } cout<<ans<<endl; } }