HDU 1102 Constructing Roads

未参考题解写的
/*
http://acm.hdu.edu.cn/showproblem.php?pid=1102
*/ 

#include <stdio.h>
#include <string.h>
#define INF 100000000
int tree[110][110];
int intree[110];
int nontree[110];
int main()
{
	freopen("input.txt","r",stdin);
	
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		memset(tree,0,sizeof(tree));
		memset(intree,0,sizeof(intree));
		memset(nontree,0,sizeof(nontree));
		int i,j;
		for(i=1; i<=n; i++)
			for(j=1; j<=n; j++)
				scanf("%d",&tree[i][j]);
		int m,a,b;
		scanf("%d",&m);
		for(i=1; i<=m; i++)
		{
			scanf("%d %d",&a,&b);
			tree[a][b]=tree[b][a]=0;//让已经相连的村庄之间的长度为0 
		}
		intree[1]=1;//选取第一个村庄为起始点 
		int non=0; // 未加入MST的村庄 
		for(i=1; i<=n; i++)
		{
			if(!intree[i])
			{
				non++; nontree[i]=1;
			}
		}	
		int sum=0;
		while(non)
		{
			int min = INF,vi=0,vj=0;
			for(i=1; i<=n; i++) //已加入MST的村庄 
			{
				if(!intree[i]) continue;
				for(j=1; j<=n; j++) // 为加入MST的村庄 
				{
					if(!nontree[j]) continue;
					if(min>tree[i][j])
					{
						min = tree[i][j];
						vj=j; vi=i;
					}
				}
			}
			if(vj)//找到最小路径 
			{
				intree[vj]=1; nontree[vj]=0;
				non--;
				sum += tree[vi][vj];
			}
		}
		printf("%d\n",sum);
	}
	return 0;
}






参考了网上的题解写的代码

prim 算法

/*
http://acm.hdu.edu.cn/showproblem.php?pid=1102
*/ 

#include <stdio.h>
#include <string.h>
#include <limits.h>

int tree[110][110]; //邻接矩阵表示点与点之间的距离 
int visit[110];    //是否已加入 MST 
int lowcost[110]; // 每个未加入 MST的点与已加入MST的点之间的 最短距离 
int sum,n;       // 总的最小费用 和 点的个数 
void prim()
{
	visit[1]=1;//选择第一个点作为起始点 
	int i,j;
	for(i=2; i<=n; i++)
		lowcost[i]=tree[1][i];	//与第一个点相连的费用 
	for(i=2; i<=n; i++) //将剩余的n-1个点 加入到 MST 
	{
		int min=0xfffffff,k=0;
		for(j=2; j<=n; j++) //选择 加入MST 的点 和未加入 MST的点之间的 最短距离 
		{
			if(!visit[j] && min>lowcost[j])
			{
				min = lowcost[j];
				k=j;
			}
		}
		sum += min;
		visit[k]=1;
		/*
		更新 lowcost 数组
		如果刚加入 MST 的节点 k 与 为加入MST的 节点 j 之间的 距离
		比 节点 j 与 之前加入MST的节点 的距离 小 则 将lowcost[j]的值设为k与j的距离即tree[k][j] 
		*/ 
		for(j=2; j<=n; j++)
		{
			if(!visit[j] && tree[k][j]<lowcost[j])
				lowcost[j]=tree[k][j];
		}
	} 
}

int main()
{
	freopen("input.txt","r",stdin);
	
	while(scanf("%d",&n)!=EOF)
	{
		memset(tree,0,sizeof(tree));
		memset(visit,0,sizeof(visit));
		memset(lowcost,0,sizeof(lowcost));
		int i,j;
		sum=0;
		for(i=1; i<=n; i++)
			for(j=1; j<=n; j++)
				scanf("%d",&tree[i][j]);
		int m,a,b;
		scanf("%d",&m);
		for(i=1; i<=m; i++)
		{
			scanf("%d %d",&a,&b);
			/*
			将已经修好的路 长度设为0 在 以后的构造最小生成树时 
			这些修好的路 一定会被 加入到最小生成树中 而且 对于最后统计的 最小费用没有影响 
			*/
			tree[a][b]=tree[b][a]=0; 
		}
		prim();
		printf("%d\n",sum);
	}
	return 0;
}









kruskal 算法

/*
http://acm.hdu.edu.cn/showproblem.php?pid=1102

kruskal 算法 

*/ 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct edge{ //表示边 
	int a,b; //边的两个顶点 
	int weight;//边的权值 
} edge;

edge road[110*110/2];//边的集合 n 个顶点最多 n*(n+1)/2 条边 

int p[110];  //表示顶点的父节点 
int tree[110][110]; //邻接矩阵 
int find(int x)
{
	return p[x]==x?x:find(p[x]);
}

void merge(int x, int y)
{
	int px,py;
	px = find(x);
	py = find(y);
	if(px!=py)
		p[py]=px; 
}

int cmp(const void* a, const void*b)
{
	return ((edge*)a)->weight- ((edge*)b)->weight;
}

int main()
{
	freopen("input.txt","r",stdin);
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		memset(road,0,sizeof(road));
		memset(tree,0,sizeof(tree));		
		int i,j,e=0;
		for(i=1; i<=110; i++) p[i]=i; //初始化 p 数组 
		for(i=1; i<=n; i++)
			for(j=1; j<=n; j++)
				scanf("%d",&tree[i][j]);
		for(i=1; i<=n; i++) //初始化边的集合 
		{
			for(j=i+1; j<=n; j++)
			{
				road[e].a=i;
				road[e].b=j;
				road[e].weight=tree[i][j];
				e++;
			}
		}
		int m,a,b;
		scanf("%d",&m);
		for(i=1; i<=m; i++)
		{
			scanf("%d %d",&a,&b);
			merge(a,b);
		}
		qsort(road,e,sizeof(road[0]),cmp); //将边根据权值 从小到大排序 
		int sum=0;
		for(i=0; i<e; i++) //根据权值 从小到大 将边加入 MST 
		{
			int pa,pb;
			pa=road[i].a;
			pb=road[i].b;
			if(find(pa)!=find(pb)) //如果边的两个顶点还没通路,则将该边加入 
			{
				sum += road[i].weight;
				merge(pa,pb);
			}
		} 
		printf("%d\n",sum);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值