题目大意:给定一张图,有n个节点,m条路,可以在每个城市修建若干个飞机场,问最少花费多少,花费相同时,输出飞机场最多的解;
题目解析:首先,这张无向图的每个强连通分量都至少有1个飞机场,为了方便计算,我们可以加一个根节点,使所有强连通分量都能与根节点连通,这样整张图就连通了,只要开始的时候预处理,多加n条边,使得图上每个点都与根节点连通就可以了,由此我们就要求出他的最小生成树,稀疏图用kurskal较好;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int n,m,pa[10010],a,cnt,nn;
struct edge
{
int u,v,w;
}e[110010];
bool cmp(edge a,edge b)
{
if(a.w==b.w)
return a.u<b.u;
return a.w<b.w;
}
int find_set(int x){
if(x==pa[x]) return x;
else return pa[x]=find_set(pa[x]);
}
int solve()
{
int i,ans=0,temp=0;
for(i=0;i<=n;i++)
pa[i]=i;
sort(e,e+nn,cmp);
i=0;
while(true)
{
int x=find_set(e[i].u);
int y=find_set(e[i].v);
if(x!=y)
{
temp++;
ans+=e[i].w;
if(e[i].u==0) cnt++;
pa[x]=y;
}
if(temp==n) break;
i++;
}
return ans;
}
int main()
{
int cas,c,i;
scanf("%d",&cas);
for(c=1;c<=cas;c++)
{
cnt=0;
nn=0;
scanf("%d%d%d",&n,&m,&a);
for(i=1;i<=n;i++)
{
e[nn].u=0;
e[nn].v=i;
e[nn].w=a;
nn++;
}
for(i=0;i<m;i++)
{
scanf("%d%d%d",&e[nn].u,&e[nn].v,&e[nn].w);
nn++;
}
int ans=solve();
printf("Case %d: %d %d\n",c,ans,cnt);
}
return 0;
}