电路实验
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
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;
}