FzrOJ 1019 电路实验

电路实验

Time Limit: 1 Second Memory Limit: 64 MB
Description

小明最近在做电路实验的时候想到了一个有趣的点子,他准备设计一个这样的电路。这个电路上面有很多灯泡(会发出红光或蓝光),灯泡之间用电线连接,然后在其中一个灯泡上接上开关,
电线间不仅能导电而且还带有信号(0或1信号),信号是这样产生和作用的:若一个灯泡发红光,则它会发出0信号,另一个与之相连的灯泡收到后,发蓝光,且发出1信号,反之亦然。

小明希望打开开关后,灯泡能全部点亮,但这时候他发现他设计的电路图出现了问题,即一个灯泡接受两种不同的信号时不会发光。小明现在准备删除一些电线,使得这个实验能够成功
(灯泡全亮),且由于经费问题,他希望删除的电线的长度和最大。由于电路图过于繁杂,他找到了聪明的你,希望你能帮他解决这个问题。 请注意:
1.只有一个开关,且开关只与一个灯泡相连。
2.打开开关,开关发出0信号。

Input

注意:测试数据有多组
第一行有两个整数n,m,代表有个灯泡,m条电线。其中开关用0表示,灯泡用1 ~ n 表示。 (0<n<=100,0<m<=5000)
接下来m行,每行有三个整数,u,v,l,表示u , v有电线连接,电线长度为l.
(输入保证两点间最多有一条电线,一个点不会与自己相连。)
(输入数据保证一定有解。)

Output

输出一个值W,表示当实验能成功时,可删除的最大电路长度和。

Sample Input

2 2
0 1 3
2 1 2
Sample Output

0



题解:

该题是一道最小生成树问题   最小生成树有两种通常算法 prim算法和kruskal算法  下面介绍的是prim算法

以这道题具体解法来讲该算法

1:首先该题输入时用一个邻接表存储,存储时按无向图存储

2:设置一个辅助数组来存储点和到该点的最小距离, 还有一个就是最小生成树数组

3:想要把提说明白 需要好多话和画图才比较好理解  ,代码中主要解决的就是上面提到的两点,存入邻接表中和更新辅助数组,代码中我会尽量详细加上注释

特:写完发现自己还是解释不清楚此题 ,我的代码是严蔚敏数据结构中最小生成树那章讲解的具体实现,大家可以先去看这本书上的讲解再来看代码估计比较容易看懂,结合书上的讲解再加上我的代码 相信大家比较容易高清pirm算法到底怎么回事了

//最小生成树问题该题用的是pirm算法 

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

struct temp{
	int w, len;//w是该点的编号,len是两点之间的长度 
	struct temp *next;
};                        //邻接表建立的结构体 
struct temp1{
	struct temp *c;
}a[105];
struct cmp{
	int before, lenmin;//辅助数组b建立的结构体, 
}b[105];
int c[105];//最小生成树数组,当该数组满时,说明所有最短点已经找完 
struct temp *f()
{
	return (struct temp *)malloc(sizeof(struct temp));
}
int main()
{
	int n, m, u, v, l, i, j, minlen, maxlen, top, count, flag1, flag2, flag3;
	struct temp *p, *q, *t;
	while(scanf("%d%d", &n, &m) != EOF)
	{
		maxlen = minlen = count = top = 0;
		for(i = 0; i < 105; i++)
		{
			a[i].c = NULL; b[i].lenmin = INT_MAX;//辅助数组的lenmin都要初始化为最大值,a数组也要初始化 
		}
		for(i = 0; i < m; i++)//这个for循环就是用来建立无向图的邻接表 
		{
			scanf("%d%d%d", &u, &v, &l); maxlen += l;//maxlen是所有电线之和 
			p = f();
			p -> len = l; p -> w = v; q = a[u].c; a[u].c = p; p -> next = q;
			p = f();
			p -> len = l; p -> w = u; q = a[v].c; a[v].c = p; p -> next = q;
		}
		c[top++] = 0;b[0].before = 0; b[0].lenmin = 0;//辅助数组的初始化,任意选择一个点放到数组中 
		while(top <= n)//这点要注意因为该题是从0开始的, 进入生成树的点要从零算起 top要<=n 
		{
			flag1 = INT_MAX;
			for(i = 0; i < top; i++)
			{
				p = a[c[i]].c;//这的for和while循环是关键这是在更新辅助数组使它符合书中所讲 
				while(p != NULL)
				{
					if(b[p->w].lenmin != 0 && b[p->w].lenmin > p->len)
					{
						b[p->w].before = c[i]; b[p->w].lenmin = p -> len;
					}
					
					p = p -> next;
				}	 
			}
			flag1 = INT_MAX;
			for(i = 0; i <= n; i++)//取出最小值   
			{
				if(b[i].lenmin != 0 && flag1 > b[i].lenmin)
				{
					flag1 = b[i].lenmin;  flag2 = i; flag3 = b[i].before; 
 				}
			}
			minlen += flag1;	b[flag2].lenmin = 0;
			c[top++] = flag2;//找到的点并入最小生成树数组 
		}
		printf("%d\n", maxlen - minlen);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值