PTA_2019春_087_公路村村通

这是一篇关于计算村落间公路连通所需最低成本的问题,输入包含城镇数目和候选道路信息,输出要求是最小成本。如果数据不足,将输出-1表示需要更多公路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

输入格式:

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

输出格式:

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

输入样例:

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
/*哈利·波特的考试*/
/*思路:1.判断是不是连通图,如果不是则输出0;
        2.多源最短路径,对联通图中的每一个顶点遍历,得到每一个顶点与其他顶点的最大长度*/
/*邻接矩阵,无向图*/
/*1.忘记加取址符
  2.错在对角线没有初始为0
  3.无解的输出位置错误 
  */
#include<stdio.h>
#include<stdlib.h>
typedef struct Gnode* MGraph;
struct Gnode {
	int Nv;  /*顶点数*/
	int Ne;  /*边数*/
	int G[101][101];  /*权重*/
};
/*边的定义,无权边*/
typedef struct Enode* Edge;
struct Enode {
	int V1, V2;
	int weight;/*权重*/
};
/*队列操作*/
typedef struct Qnode* ptrtoQnode;
struct Qnode {
	int* Data;/*data数组,*/
	int front, rear;/*队列头尾指针*/
	int maxsize;/*容量*/
};
typedef ptrtoQnode Queue;
int AddQ(Queue Q, int x);
Queue CreateQueue(int maxsize);
int isempty(Queue Q);
int DeleteQ(Queue Q);

/*操作函数*/
MGraph creatgraph(int size);
void insert(MGraph g, Edge e);
MGraph buildgraph(int N);
int isedge(MGraph graph, int a, int b);
void BFS(MGraph graph, int N, int* visited, int s);
void Floyd(MGraph graph,int weight[][101]);
/*队列操作*/
int AddQ(Queue Q, int x);
Queue CreateQueue(int maxsize);
int isempty(Queue Q);
int DeleteQ(Queue Q);

int main() {   /*注意此题从1开始*/
	int N;
	scanf("%d", &N);
	int* visited = (int*)malloc((N+1) * sizeof(int));
	int isanswer = 1;
	for (int i = 1; i < N+1; i++) {
		visited[i] = 0;
	}
	/*建立邻接矩阵*/
	MGraph graph = buildgraph(N);

	BFS(graph, N, visited, 1);/*以第一个顶点为起点,对图进行遍历,如果图中有顶点未被遍历过则说明不是联通图*/
	for (int i = 1; i < N + 1; i++) {
		if (visited[i] == 0)  {
			isanswer = 0;
			break;
		}
	}
	/*多源最短路径*/
	int weight[101][101];
	int shortest[101];
	Floyd(graph, weight);
	for (int i = 1; i < N + 1; i++) {
		int max = -1;
		for (int j = 1; j < N + 1; j++) {
			if (weight[i][j] > max && weight[i][j] != 20000) {
				max = weight[i][j];
			}	
		}
		shortest[i] = max;/*将与第i个顶点路径最长的存储*/
	}
	/*先将shortest存储*/
	int data[101];
	for (int i = 1; i < N + 1; i++) {
		data[i] = shortest[i];
	}
	/*对shortest排序,找出其最小值*/
	int j;
	int temp;
	for (int i = 1; i < N ; i++) {   /*shortest最小值即第一元素*/
		for (j = i + 1; j < N + 1; j++) {
			if (shortest[i] > shortest[j]) {
				temp = shortest[i];
				shortest[i] = shortest[j];
				shortest[j] = temp;
			}
		}
	}
	/*找出最小编号*/
	int answer;
	for (int i = 1; i < N + 1; i++) {
		if (shortest[1] == data[i]) {
			answer = i;
			break;
		}
	}
	if(isanswer == 1){
		printf("%d %d", answer, data[answer]);
	}
	else  printf("0");
	return 0;
}
MGraph creatgraph(int size) {/*初始化邻接矩阵*/
	int j;
	MGraph graph = (MGraph)malloc(sizeof(struct Gnode)); /*建图*/
	graph->Nv = size;
	graph->Ne = 0;
	/*初始化邻接矩阵*/
	for (int i = 1; i < graph->Nv+1; i++) {
		for (j = 1; j < graph->Nv+1; j++) {
			if(i==j){                                /*一开始没有将对角线处初始为0,导致最后多源最短路径出错*/
				graph->G[i][j] = 0; 
			}
			else{
				graph->G[i][j] = 20000;             /*设20000为无穷值,即两点不连通*/
			}
			                     
		}
	}
	return graph;
}
void insert(MGraph g, Edge e) {  /*注意此题为无向图*/
	g->G[e->V1][e->V2] = e->weight;
	g->G[e->V2][e->V1] = e->weight;
}
MGraph buildgraph(int N) {
	MGraph G;
	G = creatgraph(N);
	scanf("%d", &G->Ne);
	if (G->Ne != 0) {
		Edge E = (Edge)malloc(sizeof(struct Enode));
		for (int i = 0; i < G->Ne; i++) {
			scanf("%d %d %d", &E->V1, &E->V2,&E->weight);
			insert(G, E);
		}
	}
	return G;
}
Queue CreateQueue(int maxsize) {
	Queue Q = (Queue)malloc(sizeof(struct Qnode));
	Q->Data = (int*)malloc(maxsize * sizeof(int));
	Q->front = Q->rear = 0;
	Q->maxsize = maxsize;
	return Q;
}
int AddQ(Queue Q, int x) {
	Q->rear = (Q->rear + 1) % (Q->maxsize);
	Q->Data[Q->rear] = x;
	return 1;
}
int isempty(Queue Q) {
	return(Q->rear == Q->front);
}
int DeleteQ(Queue Q) {
	Q->front = (Q->front + 1) % Q->maxsize;
	return Q->Data[Q->front];
}
int isedge(MGraph graph, int a, int b) {
	return graph->G[a][b] < 20000 ? 1 : 0;
}
void BFS(MGraph graph, int N, int* visited, int s) {
	Queue Q;
	int v, w;
	Q = CreateQueue(N);
	
	visited[s] = 1;
	AddQ(Q, s);
	while (isempty(Q) == 0) {
		v = DeleteQ(Q);
		for (w = 1; w < graph->Nv + 1; w++) {/*遍历图中的每一个顶点*/
			if (visited[w] == 0 && isedge(graph, v, w)==1) {
				visited[w] = 1;
				AddQ(Q, w);
			}
		}
	}
}
void Floyd(MGraph graph,int weight[][101]) {
	int i, j, k;
	for (i = 1; i < graph->Nv + 1; i++) {
		for (j = 1; j < graph->Nv + 1; j++) {
			weight[i][j] = graph->G[i][j];
		}
	}
	for (k = 1; k < graph->Nv + 1; k++) {
		for (i = 1; i < graph->Nv + 1; i++) {
			for (j = 1; j < graph->Nv + 1; j++) {
				if (weight[i][k] + weight[k][j] < weight[i][j]) {
					weight[i][j] = weight[i][k] + weight[k][j];
				}
			}
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值