数据结构-造树计划-最小生成树
最小生成树
思路
-
沿某一点绕一圈,遇到最小的点往路径最小的点走
-
并用p[]数组来记录该点的父结点
p[v]=u
(表示v的父节点是u),方便求出路径和sum+=G[i][p[i]]
-
如果说p[v]=提前设定好的值,也就是说它没有被改变,那么要么这个点是出发点,要么这个点是被“隔离”的。
-
加强理解的手段,用color数组,取三个值分别表示已经被用(BLACK),要被用(GRAY)和还没有探索到(WHITE)
-
确定新起点(注意原起点打通了与新起点的通道(使得这些点变成了灰色(缓冲点)),
d[v]=d[u][v]
) -
注意:可能还要考虑重边和自环
AC代码P3366 【模板】最小生成树
#include<iostream>
#include<stdio.h>
using namespace std;
static const int MAX=5005;
static const int WHITE=0;//表示未用过的点
static const int GREY=1;//表示待用的点
static const int BLACK=2;//表示用过的点
static const int INFTY=999999;
int G[MAX][MAX];
int p[MAX];
int color[MAX];
int d[MAX];
int num,n;
void prim()
{
//初始化
for(int i=1;i<=num;i++)
{
p[i]=-1;
color[i]=WHITE;
d[i]=INFTY;
}
d[1]=0;
while(1)
{
int u=-1;
int minv=INFTY;
// cout<<2<<endl;
for(int i=1;i<=num;i++)
{
// cout<<3<<endl;
if(d[i]<minv&&color[i]!=BLACK)
{
// cout<<4<<endl;
u=i;
// cout<<u<<endl;
minv=d[i];
}
}
if(u==-1)break;
color[u]=BLACK;
for(int v=1;v<=num;v++)
{
if(color[v]!=BLACK&&d[v]>G[u][v]&&u!=v)
{
color[v]=GREY;
d[v]=G[u][v];
p[v]=u;
}
}
}
int total=0;
int flag=1;
for(int v=2;v<=num;v++)
{
// cout<<6<<endl;
if(p[v]==-1)
{
flag=0;
cout<<"orz";
break;
}
total+=G[v][p[v]];
// cout<<p[v]<<" "<<G[v][p[v]]<<" "<<total<<endl;
}
if(flag)cout<<total;
}
int main()
{
cin>>num>>n;
for(int i=1;i<=num;i++)
{
for(int j=1;j<=num;j++)
{
G[i][j]=INFTY;
G[j][i]=INFTY;
}
}
for(int i=1;i<=n;i++)
{
int s,t,e;
cin>>s>>t>>e;
if(G[s][t]>=e)
{
G[s][t]=e;
G[t][s]=e;
}
//cout<<G[s][t];
}
prim();
return 0;
}
其他
距离无穷大
static const int INFTY =(1<<21);
参考资料
-
挑战程序设计竞赛
-
zjl大佬