POJ 1258 最小生成树

思路:求最小生成树无非是两种思路,用prim()算法或者克鲁斯算法。prim算法就是对一棵先拆成每个独立的点,随便找到一个点,然后比较与该点相连的所有点中权值最小的,然后把该权值加入到一个用来你保存最小生成树中的权值,然后把点加入到用来保存已选取点的数组,并对该顶点做一个标记,表示该顶点已经加入到数组中,再选取该顶点中与它相连顶点中权值最小的,以此类推。若是某个顶点与它所有相连的顶点都已经添加进去了,在剩下的顶点中选取一个顶点重新操作就好了。     由此可见,prim算法主要是根据顶点来选出最小生成树。  但是克鲁斯算法则是根据边的权值来确定的,在所有边中选取权值最小的,然后确定它的顶点,把权值跟两端的顶点分别添加到数组中,继续选权值最小的,继续添加顶点,判断是否已经存在于里面了,如果已经存在,自然是不用添加的。以此类推,直到把无向图连通,生成树就选出来了


#include<iostream>

using namespace std;
#define  inf  1<<29
#define  max  101
int  map[max][max];
int n;   

void  prim()  //构造最小生成树
{
int i, j;
int d[max];   //用来存储权值
int mi;//用来表示当前最小的
int vis[max];//用来存储选出来的顶点
int  v;//表示当前结点
for ( i = 1; i <= n; i++)
{
d[i] = map[1][i]; //把矩阵中第一行的所有值传入d数组中
vis[i] = 0;   //对所有已选中的结点初始化
}
for (i = 1; i <= n; i++)
{
mi = inf;//设定一个最小值 
for (j = 1; j <= n; j++)
{
if (!vis[j] && d[j]< mi)//找出与第i个顶点有联系的所有路径中最小的一条
{
mi = d[j];//找到一个路径最小的长度
v = j;  //把当前最小的权值的位置记录下来
}
}
vis[v] = 1;//标记某个顶点已经存在于保存选中的顶点数组中
for (j = 1; j <= n; j++)
{
if (!vis[j] && d[j]> map[v][j])//如果某个顶点不存与选中的数组中,且初始化给定的权值至少大于至少该顶点与其他顶点相连中的权值
{
d[j] = map[v][j];//更新当前位置的权值
}
}
}
for (d[0] = 0, i = 1; i <=n; i++)//把所有选出的权值求和
{
d[0] += d[i];
}
cout << d[0] << endl;
}


int main()
{
int i, j;//只是下标

while (cin>>n)
{
//利用一个矩阵存储所有的权值
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
cin >> map[i][j];
}
}
prim();  //调用prim()
}
system("pause");
return  0;

}


-------------------------------

克鲁斯卡尔算法

#include<iostream>
using namespace std;
int map[101][101];
int father[10001];
int find(int x)
{
int r = x;
while (r != father[r])
r = father[r];
int temp;
while (r != x)
{
temp = father[x];
father[x] = r;
x = temp;
}
return r;
}
void merge(int x, int y)
{
father[x] = y;
}
int main()
{
int n;
while (cin >> n)
{
int i, j, k;
//memset(visited,0,sizeof(visited));
for (i = 0; i <= n*n; i++)
father[i] = i;
memset(map, 0, sizeof(map));
for (i = 0; i<n; i++)
for (j = 0; j<n; j++)
scanf("%d", &map[i][j]);
int x, y;
int sum = 0;
int fx, fy;
for (i = 1; i<n; i++)
{
int min = 1000000;
for (j = 0; j<n; j++)
for (k = j; k<n; k++)
{


if (map[j][k]<min)
{
x = find(j);
y = find(k);
//    cout<<x<<"  "<<y<<endl;
if (x != y)
{
//    cout<<"x:"<<x<<" "<<"y:"<<y<<endl;
min = map[j][k];
fx = x;
fy = y;
//merge(x,y);
}
}
}
merge(fx, fy);
//    cout<<"min:"<<min<<endl;
sum += min;
}
cout << sum << endl;
}
return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值