最小生成树(有n个结点的连通图最小权重)
1.Prim算法(对点的选取加入)
用二维数组记录点和权值。先选取一个点作起始点,然后任选一个邻近未访问过的权值最小点,重复直到选出n个点。
#define INF 0x7FFFFFFF
int w[510][510];
int v[510],low[510];
//low[i]记录当前在S内, 未访问点到点i的最小距离
int main()
{
int t,n,maxx,sum;
bool first = true;
cin >> t;
while(t--)
{
cin>>n;
sum = maxx = 0;
memset(v,0,sizeof(v));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>w[i][j]; //邻接矩阵
v[1] = 1; //从点1开始,初始化设离点i最近的点是点1
for(int i=2;i<=n;i++) low[i] = w[1][i];
for(int i=1;i<n;i++)
{
int x=1, m=INF;
for(int j=1;j<=n;j++)//找出未访问的最小low[j]点x
if(!v[j]&&low[j]<m){
x = j;
m = low[j];
}
v[x] = 1;
sum += m;
if(maxx<m) maxx = m;
for(int j=2;j<=n;j++){ //更新未访问点到点i的最短边
if(!v[j]&&low[j]>w[x][j])
low[j] = w[x][j];
}
}
if(first) first=false;
else cout<<endl;
cout << maxx << " "<< sum<<endl;
} //sum为最小生成树总长度,maxx为其中的最长边
return 0;
}
2.kruskal算法(对边的选择)
将所有边按权值从小到大排序,从权值最小边开始遍历每条边,直至图中所有节点都在同一个连通分量中
#define N 510
int father [N];
struct point{
int x,y,len;
}pot[N*N];
int cmp(point x,point y){
return x.len<y.len;
}
int find(int x){ //使用并查集
while(x!= father [x])
x= father [x];
return x;
}
int main()
{
int t,n,maxx,sum,a,b;
cin >> t;
while(t--)
{
cin>>n;
sum = maxx = 0;
int q = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
cin>>pot[q].len;
pot[q].x = i;
pot[q++].y = j;
}
sort(pot,pot+q,cmp);
for(int i=1;i<=n;i++) father[i]=i;
for(int i=0;i<q;i++) //遍历选边
{
a = find(pot[i].x);
b = find(pot[i].y);
if(a!=b){ //不连接成环就加入此边
sum += pot[i].len;
if(pot[i].len>maxx)
maxx=pot[i].len;
father [b]=a;
}
}
cout <<sum<<" "<< maxx <<endl;
}
return 0;
}