hihocoder #1160 : 攻城略地
描述
A、B两国间发生战争了,B国要在最短时间内对A国发动攻击。已知A国共有n个城市(城市编号1, 2, …, n),城市间有一些道路相连。每座城市的防御力为w,直接攻下该城的代价是w。若该城市的相邻城市(有道路连接)中有一个已被占领,则攻下该城市的代价为0。
除了占领城市,B国还要摧毁A国的交通系统,因而他们需要破坏至少k条道路。由于道路损毁,攻下所有城市的代价相应会增加。假设B国可以任意选择要摧毁的道路,那么攻下所有城市的最小代价是多少?
解题报告:
用时:1h30min
正解:贪心
首先要看懂题目:要使得去掉k条边后每一个联通块最小值之和最小,那么就简单了,直接贪心:我们要将权值小的贡献尽量多,所以我们可以先使得整个图连通,然后选择最小的几个作为最小值,单独成连通块,并查集维护即可
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=1e6+5;
int val[N],n,m,k,fa[N],v[N],q[N],kase=0;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void work()
{
int x,y,cnt=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]),fa[i]=i,v[i]=val[i];
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if(find(x)==find(y)){k--;continue;}
if(v[find(x)]<v[find(y)])swap(x,y);
v[find(x)]=v[find(y)];
fa[find(x)]=find(y);
}
long long ans=0;
for(int i=1;i<=n;i++)
if(fa[i]==i)ans+=v[i];
else q[++cnt]=val[i];
sort(q+1,q+cnt+1);
for(int i=1;i<=k;i++)ans+=q[i];
printf("Case #%d: %lld\n",++kase,ans);
}
int main()
{
int T;cin>>T;
while(T--)work();
return 0;
}