【问题描述】
某单位服务器集群网络结构呈树型结构,网络中节点可为交换机和服务器二种设备,服务器只能位于树的叶节点上。在该网络结构中正常工作的服务器每天定时向外广播心跳信息(即是否正在工作)(心跳技术,Heartbeat)。
编写一程序根据设备心跳记录日志分析是否存在运行故障设备,并报告可能存在的故障设备。心跳记录日志文件存储在根交换机,且根交换机不会出现故障,其中的每条记录只由服务器设备号(只要收到信息就表示状态正常)组成。诊断规则如下:
1)根交换机若没有收到某个服务器的心跳信息,但收到该服务器同属交换机下(不仅包括同层,也包括下面层)的服务器心跳信息,则诊断该服务器可能出错;例如下图中:若没有收到3号服务器的心跳信息,但收到6号服务器的心跳信息,则诊断3号服务器可能出错。
2)根交换机若没有收到某个交换机下(不仅包括同层,也包括下面层)的所有服务器心跳信息,则诊断该交换机可能出错(如果多个交换机满足条件,则只报最上层交换机故障)。例如下图中:若收到了15号服务器的心跳信息,但没有收到21号、22号和23号服务器的心跳信息,则只报13号交换机故障。
test.png
【输入形式】
首先输入设备配置表中设备的数目,然后按如下格式分行输入设备配置表中每个设备的信息:
设备号(0-2000) 父设备(交换机)号 端口号(1-32) 设备类型(0表示交换机,1表示服务器)
上面设备信息数据间以一个空格分隔,输入的设备编号是无序的(但保证输入一个设备信息时,其父设备信息已经输入);
最后输入发出心跳的服务器号,以-1结束:
服务器号1 服务器号2 … -1(以一个空格分隔的服务器号序列,收到的心跳记录是无序的)。
注意:根设备肯定为交换机,没有父设备,其位于配置表的第一行,因此设备配置表的第一行一定为0 -1 -1 0。
【输出形式】
按前序遍历序输出可能出现故障的设备号,各数据间以一个空格分隔。前序遍历的原则为先访问根结点,然后根据端口号(从1至32)依次按照前序遍历的原则访问子树中的结点。
【样例输入】
37
0 -1 -1 0
4 0 5 0
5 4 2 1
7 4 8 0
29 4 10 1
13 7 16 0
15 7 26 1
14 13 1 0
23 13 2 1
21 14 2 1
22 14 5 1
27 14 8 0
8 0 32 0
16 8 27 0
17 16 2 0
28 16 5 0
30 16 7 0
18 17 5 1
31 28 3 0
33 30 3 1
32 31 2 1
34 31 8 1
35 31 12 0
36 35 15 1
1 0 1 0
2 1 2 0
3 1 3 1
9 2 1 0
6 2 9 1
10 9 2 0
12 9 3 0
19 9 5 1
11 10 3 1
20 12 2 0
24 12 5 1
25 20 2 0
26 20 5 1
18 32 36 21 22 5 23 6 3 -1
【样例输出】
9 27 15 29 34 30
【样例说明】
输入了37个设备的信息,构成了如上图所示的集群树型结构。根交换机收到了9个服务器发出的心跳记录。由于收到了6号服务器的心跳记录,但没有收到9号交换机下所有服务器的心跳信息,所以判定9号交换机可能故障,其下的所有设备不再报故障;由于收到了23号服务器的心跳记录,说明7号交换机没有故障,但没收到其下的15号服务器的心跳信息,所以可判定15号服务器可能故障;其它判定类似......。
【评分标准】
该要求查找可能出现故障的设备,提交程序名为beat.c。
【思路】
收录一位佬的代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 2048
typedef struct Node {
int id;
int type;
int fa_id;
int height;//dfs序深度
int deep;//bfs序深度
int rank;//接在父节点的几号子树上
struct Node* ch[8], * fa;
}Node;
int n, tar_id;
Node* getNewNode(int id, int type)
{
Node* p = (Node*)malloc(sizeof(Node));
p->type = type;
p->id = id;
p->fa_id = 0;
p->rank = 0;
p->deep = 0;
p->height = 0;
for (int i = 0;i < 8;i++)
{
p->ch[i] = NULL;
}
p->fa = NULL;
return p;
}
void insert(Node* root, Node* tar)
{
if (root->id == tar->fa_id)
{
root->ch[tar->rank] = tar;
tar->fa = root;//建立回溯线索
return;
}
for (int i = 0;i < 8;i++)
{
if (root->ch[i] != NULL)
{
insert(root->ch[i], tar);
}
}
return;
}
//节点dfs序深度标记
int k = 0;
void dfs(Node* root)
{
root->height = k++;
for (int i = 0;i < 8;i++)
{
if (root->ch[i] != NULL)
{
dfs(root->ch[i]);
}
}
return;
}
//带回溯指针的树的遍历相当于图的遍历,需要搜索去重,防止重复搜索某个节点
Node* ans[1005];//存储得到的打印机序
int cnt;
int vis[1005];//地图不能重复遍历
Node* que[1005];
int head, tail;
void bfs(Node* root)//这里把sig节点看成树的根节点,相当于对树进行翻转
{
que[tail++] = root;
while (head < tail)
{
Node* tmp = que[head++];
if (tmp->type == 2)
{
ans[cnt++] = tmp;
}
//只有0号是转换器,可以向孩子节点转移,
if (tmp->type == 0)
{
for (int i = 0;i < 8;i++)
{
if (tmp->ch[i] != NULL && vis[tmp->ch[i]->id] == 0)
{
vis[tmp->ch[i]->id] = 1;//标记访问
que[tail] = tmp->ch[i];
que[tail]->deep = tmp->deep + 1;
tail++;
}
}
}
//所有节点都可以向父节点转移
if (tmp->fa != NULL && vis[tmp->fa->id] == 0)
{
vis[tmp->fa->id] = 1;
que[tail] = tmp->fa;
que[tail]->deep = tmp->deep + 1;
tail++;
}
}
return;
}
int main()
{
int r;
Node* sig = NULL;//指向目标计算机编号的节点
scanf("%d",&r);
int id = 0, type = 0, fa = 0, rank = 0;
scanf("%d %d %d %d", &id, &fa, &type, &rank);
Node* root = getNewNode(id, type);
for (int i = 0;i < n-1;i++)
{
scanf("%d %d %d %d", &id, &fa, &type, &rank);
Node* tar = getNewNode(id, type);
tar->fa_id = fa;
tar->rank = rank;
if (id == tar_id)sig = tar;
insert(root, tar);
}
int numset[200];
int y=1;
int u=0;
while(y)
{
scanf("%d",numset[u++]);
if(numset[u-1]==-1)
{
y=0;
}
}
return 0;
}