这里提供两种方法:prim和并查集,prim就是直接模版,求出权值和最小的图,第二种就是kruscal,用于较稀疏的图
题目链接 点击打开链接
prim 代码注释:
<span style="font-size:18px;color:#ff6600;"><strong>#include<iostream>
#include<cstring>
using namespace std;
#define INF 0xfffffff
#define N 105
int a[N][N],visit[N],dis[N];
int prim(int n)
{
int i,sum=0;
memset(visit,0,sizeof(visit));
for(i=1; i<=n; i++) //这里我从点1开始查找,可以是小于等于n的任意值,a[1...n][i]
dis[i]=a[1][i];
visit[1]=1; //记得标记
int t=n-1; //少循环一次
while(t--)
{
int min=INF;
int temp=-1;
for(i=1; i<=n; i++)
{
if(!visit[i]&&dis[i]<min) //找距初始点最近的点
{
min=dis[i];
temp=i;
}
}
if(temp==-1) //说明没有与之相连的点,返回
return -1;
visit[temp]=1; //标记
sum+=min; //循环每次加上最小值
for(i=1; i<=n; i++)
{
if(!visit[i]&&a[temp][i]<dis[i]) //更新新的点周围点的权值
dis[i]=a[temp][i];
}
}
return sum;
}
int main()
{
int n,m,i,j;
while(cin>>n>>m,n)
{
for(i=1; i<=m; i++)
for(j=1; j<=m; j++)
{
if(i==j)
a[i][j]=0;
else
a[i][j]=INF;
}
while(n--)
{
int x,y,v;
cin>>x>>y>>v;
if(v<a[x][y]) //防止相同两点不同权值,取较小
a[x][y]=a[y][x]=v;
}
int ans=prim(m);
if(ans==-1)
cout<<"?"<<endl;
else
cout<<ans<<endl;
}
}
</strong></span>
<span style="font-size:18px;color:#ff6600;"><strong>#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
struct F
{
int a,b,p; //a,b为一条边两点,p为权值
} edge[105];
int father[105];
bool cmp(F a,F b)
{
return a.p<b.p;
}
int find(int x)
{
while(x!=father[x])
x=father[x];
return x;
}
void Union(int x,int y)//将元素归入集合,或者说建图
{
x=find(x);
y=find(y);
father[x]=y;
}
int main()
{
int i,n,m;
while(scanf("%d%d",&n,&m),n!=0)
{
for(i=1; i<=m; i++)//初始化
father[i]=i;
for(i=1; i<=n; i++)
scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].p);
sort(edge+1,edge+n+1,cmp); //贪心,排序
int sum=0;
for(i=1; i<=n; i++)
{
int X=find(edge[i].a);
int Y=find(edge[i].b);
if(X!=Y)
{
Union(X,Y); //连接两个点 ,同时减去一条边
m--;
sum+=edge[i].p;
}
}
if(m==1) //连通图已建成
cout<<sum<<endl;
else
cout<<"?"<<endl;
}
}</strong></span>