PTA 08-图7 公路村村通 (30分)

题目地址

https://pta.patest.cn/pta/test/15/exam/4/question/718

5-10 公路村村通   (30分)

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数NN(le 10001000)和候选道路数目MM(le 3N3N);随后的MM行对应MM条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到NN编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出-11,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

此题考查最小生成树
/*
评测结果
时间	结果	得分	题目	编译器	用时(ms)	内存(MB)	用户
2017-07-05 09:16	答案正确	30	5-10	gcc	36	1	
测试点结果
测试点	结果	得分/满分	用时(ms)	内存(MB)
测试点1	答案正确	15/15	1	1
测试点2	答案正确	2/2	17	1
测试点3	答案正确	2/2	1	1
测试点4	答案正确	5/5	36	1
测试点5	答案正确	6/6	21	1
*/
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAXN 1000
#define INFINITY 100000
#define ERROR -1
typedef struct Edge* pEdge;
struct Edge
{
	pEdge next;
	int v;
	int cost;
};

struct Vertex
{
	pEdge head;
	int collectedFlag;
	int totalCost;
	int from;
} gVertexTable[MAXN];

void InitVertex() //初始化顶点列表
{
	int i;
	for(i=0;i<MAXN;i++)
	{
		gVertexTable[i].head=NULL;
		gVertexTable[i].collectedFlag=FALSE;
		gVertexTable[i].from=0;
		gVertexTable[i].totalCost=INFINITY;
	}
}

pEdge CreateEdge() //创建新的边节点
{
	pEdge E;
	E=malloc(sizeof(struct Edge));
	E->next=NULL;
	return E;
}

void InsertEdge(int a,int b,int cost) //插入边
{
	pEdge E=CreateEdge();
	E->v=b;
	E->cost=cost;
	E->next=gVertexTable[a].head;
	gVertexTable[a].head=E;
}

int FindAnyVertex(int N) //随便选一个有边的点当起点
{
	int i,tmp;
	for(i=0;i<N;i++)
	{
		if(gVertexTable[i].head!=NULL)
			return i;
	}
}

int FindNextVertex(int N) //找下一个离收录集合最近的点
{
	int i;
	int minCost=INFINITY;
	int minIDX=-1;
	for(i=0;i<N;i++)
	{
		if(gVertexTable[i].collectedFlag==FALSE && gVertexTable[i].totalCost<minCost)
		{
			minIDX=i;
			minCost=gVertexTable[i].totalCost;
		}
	}
	return minIDX;
}

void FindMinCost(int N)
{
	int i,k;
	int sumCost=0;
	pEdge tempE;
	while((i=FindNextVertex(N))!= ERROR) //最外层,找一个集合外的,离集合距离最近的点
	{
		sumCost+=gVertexTable[i].totalCost; //把这个点收入集合,边长累加
		gVertexTable[i].collectedFlag=TRUE;
		gVertexTable[i].totalCost=0;

		for(k=0;k<N;k++) //内层,遍历已在集合内的点
		{
			if(gVertexTable[k].collectedFlag==FALSE)
				continue;
			tempE=gVertexTable[k].head;
			while(tempE!=NULL) //遍历集合内的点的每条边,计算到集合外的距离
			{
				if(gVertexTable[tempE->v].totalCost>gVertexTable[i].totalCost+tempE->cost)
				{
					gVertexTable[tempE->v].totalCost=gVertexTable[i].totalCost+tempE->cost;
//					printf("%d->%d |tempE->cost=%d
",i,tempE->v,tempE->cost);
					gVertexTable[tempE->v].from=i;
				}
				tempE=tempE->next;
			}
		}
	}
	
	for(i=0;i<N;i++) 
	{
		if(gVertexTable[i].collectedFlag==FALSE)//如果有点没被收进来,说明整个图没有完全连通
		{
			printf("-1");
			return;
		}
	}
	
	printf("%d",sumCost); //输出最小生成树的长度
}

int main()
{
	int N,M;
	int i,v1,v2,cost,startVertex;
	InitVertex();
	scanf("%d %d",&N,&M);
	for(i=0;i<M;i++)
	{
		scanf("%d %d %d",&v1,&v2,&cost);
		InsertEdge(v1-1,v2-1,cost);//输入的值范围是1-N,减1换算成下标范围
		InsertEdge(v2-1,v1-1,cost);
	}
	startVertex=FindAnyVertex(N); //随便找个非空节点当起点
	gVertexTable[startVertex].totalCost=0;//距离置零,方便在第一次搜索中找到。
	gVertexTable[startVertex].from=startVertex;
	FindMinCost(N);
}

  

原文地址:https://www.cnblogs.com/gk2017/p/7141087.html