1.题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3371
2.思路:
给出n个点,m条边,以及k组已经修好的路,问联通所有城市要需要至少多少的修路费。
3.参考代码:
代码一:并查集
#include <stdio.h>
#include <algorithm>
using namespace std;
#define N 505
int root[N];
struct node{
int u,v,w;
}edge[N*N];
int cmp(node x,node y){
return x.w<y.w;
}
int find(int x){
if(x==root[x])
return x;
return root[x]=find(root[x]);
}
int main()
{
int t,n,m,k,i,x,y,num,rt,a,ans;
scanf("%d",&t);
while(t--)
{
for(i=0;i<=N;i++) ///一定要从0开始,不然会WA
root[i]=i; ///初始化并查集
int flag=0;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
sort(edge+1,edge+m+1,cmp); ///将边排序
while(k--)
{
scanf("%d%d",&num,&rt);
for(i=1;i<num;i++)
{
scanf("%d",&a);
x=find(a);
y=find(rt);
if(x!=y)
root[x]=y;
}
}
for(num=0,i=1;i<=n;i++)
{
if(root[i]==i)
num++;
}
for(ans=0,i=1;i<=m;i++)
{
x=find(edge[i].u);
y=find(edge[i].v);
if(x!=y)
{
root[x]=y;
ans+=edge[i].w;
num--;
}
if(num==1) ///num==1说明只有能够并成一棵树
{
flag=1;
break;
}
}
if(flag)
printf("%d\n",ans);
else
printf("-1\n");
}
return 0;
}
代码二:prime算法
#include <stdio.h>
#define inf 0xffff
#define N 505
int n,m;
int edge[N][N];
int lowcost[N]; ///记录最低费用
int vis[N];
void prime(){
sum=0,cnt=0;
for(i=1;i<=n;i++)
{
lowcost[i]=edge[1][i];
vis[i]=0;
}
vis[1]=1;
for(i=1;i<=n;i++)
{
int min=inf;
for(j=1;j<=n;j++)
{
if(min>lowcost[j] && !vis[j])
{
min=lowcost[j];
pos=j;
}
}
vis[pos]=1;
sum+=min;
cnt++; ///边数加一
if(min==inf)
break;
for(j=1;j<=n;j++)
{
if(lowcost[j]>lowcost[pos]+edge[pos][j] && !vis[j])
lowcost[j]=lowcost[pos]+edge[pos][j];
}
}
if(cnt==n-1) ///边数等于点数加一
printf("%d\n",sum);
else
printf("-1\n");
}
int main()
{
int t,k,i,j,u,v,w,num,a[111111];
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
edge[i][j]=inf;
}
while(m--)
{
scanf("%d%d%d",&u,&v,&w);
if(edge[u][v]>w)
edge[u][v]=edge[v][u]=w;
}
while(k--)
{
scanf("%d",&num);
for(i=1;i<=num;i++)
scanf("%d",&a[i]);
for(i=1;i<=num;i++)
{
for(j=1;j<=num;j++)
{
if(i!=j)
edge[a[i]][a[j]]=edge[a[j]][a[i]]=0;
}
}
}
prime();
}
return 0;
}