NOj-1405(Prim()

也是一个很好的贪心的程序,

具体看代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
/*
 *这是用Prim来解决Minimal Spanning Tree的问题,
 *当然Kruskal和Prim都是利用的贪心思想,而Kruskal更是将贪心的思想体现的淋漓尽致,,
 *但是Prim也是不错的想法,
 *思想的主要特征就是随机选取一个点作为起点a,(一般选取第一个点做为起点)然后选取距离
 *此点的权值最小的点b,更新这个点的权值dis[b],当然要标记a这个点已经访问vis[i] = 1, 
 *然后每次找到最小的dis值,做为起点,找寻距离此点最小的下一个邻接点,并且更新它.
 *当最后全部更新完毕的时候就结束后了一共需要进行 
 */

using namespace std;

const int INF = 0x3f3f3f3f; // 定义int型的最大值INF 相当于正无穷,当然定义成0x3f3f3f3f应该也可以解决这个问题,
							//但是不够严密; 

int N;

int M;

int map[105][105];

int vis[105];

int dis[105];

void Init()
{
	memset(map, 0x3f, sizeof(map));//其实这样是不是很好的,因为0x3f3f3f3f并不是真正意义上的正无穷,不过
									//由于memset的效率比较高,还是比较倾向于这样赋值;
	/*
	for (int i = 0; i < 105; i++)
	{
		for (int j = 0; j < 105; j++)
		{
			map[i][j] = INF;
		}
	}   // 用了for循环来赋值,也是15ms,好像体现不出优越性呀,,,,诶,, 
	*/
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= N; i++)
	{
		dis[i] = INF;
		map[i][i] = 0; // 其实这个也是有必要的,自己距离自己的权值是0; 
	}	
}

int Prim()
{
	dis[1] = 0;
	for (int i = 1; i <= N; i++) // 其实可以不用运行N次, 只用到N-1次的时候就已经把所有的边都存到dis中了 
	{
		int t = INF;
		int pos;
		for (int j = 1; j <= N; j++)
		{
			if (!vis[j] && t > dis[j])//用t来筛选出此时没有被访问,并且dis的值最小的点 
			{
				t = dis[j];
				pos = j;
			}
		}
		vis[pos] = 1;//标记这个点已经被访问了 
		for (int j = 1; j <= N; j++)
		{
			if (!vis[j] && map[pos][j] != 0x3f3f3f3f && dis[j] > map[pos][j])//首先
							//需要满足的就是与pos向邻接,并且dis存的值需要更新的时候才执行 
			{
				dis[j] = map[pos][j];
			}
		}
	}
	int sum = 0;
	for (int i = 1; i <= N; i++)
	{
		sum += dis[i];//把所有的dis值都加上,就是所求的最小生成树的解 
	}
	return sum;
}
	

int main()
{
	while (scanf("%d%d", &N, &M) != EOF)
	{
		Init();
		int a, b, val;
		for (int i = 1; i <= M; i++)
		{
			scanf("%d%d%d", &a, &b, &val); 
			if (map[a][b] > val)//其实这一步还是有必要的,判断,当有重边的时候,可以选取边最小的val,不多余; 
			{
				map[a][b] = val;
				map[b][a] = val;
			}
		}
		int ans = Prim();
		printf("%d\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值