這裏提供兩種方法: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>