(这个题貌似比第三题难,但是第三题属实折磨我更久)
题面如下
【问题描述】
某单位信息网络结构呈树型结构,网络中节点可为交换机、计算机和打印机三种设备,计算机和打印机只能位于树的叶节点上。如要从一台计算机上打印文档,请为它选择最近(即经过交换机最少)的打印机。
在该网络结构中,根交换机编号为0,其它设备编号可为任意有效正整数,每个交换机有8个端口(编号0-7)。当存在多个满足条件的打印机时,选择按树前序遍历序排在前面的打印机。
【输入形式】
首先从标准输入中输入两个整数,第一个整数表示当前网络中设备数目,第二个整数表示需要打印文档的计算机编号。两整数间以一个空格分隔。假设设备总数目不会超过300。
然后从当前目录下的in.txt读入相应设备配置表,该表每一行构成一个设备的属性,格式如下:
<设备ID> <类型> <设备父节点ID> <端口号>
<设备ID>为一个非负整数,表示设备编号;<类型>分为:0表示交换机、1表示计算机、2表示打印机;<设备父结点ID>为相应结点父结点编号,为一个有效非负整数;<端口号>为相应设备在父结点交换机中所处的端口编号,分别为0-7。由于设备配置表是按设备加入网络时的次序编排的,因此,表中第一行一定为根交换机(其属性为0 0 -1 -1);其它每个设备结点一定在其父设备结点之后输入。每行中设备属性间由一个空格分隔,最后一个属性后有换行符。
【输出形式】
向控制台输出所选择的打印机编号,及所经过的交换机的编号,顺序是从需要打印文档的计算机开始,编号间以一个空格分隔。
【样例输入】
37 19
in.txt中的信息如下:
0 0 -1 -1
1 0 0 0
2 0 1 2
3 1 1 5
4 0 0 1
5 1 4 0
6 2 2 2
7 0 4 2
8 0 0 4
9 0 2 0
10 0 9 0
11 2 10 3
12 0 9 2
13 0 7 0
14 0 13 0
15 2 7 3
16 0 8 1
17 0 16 0
18 1 17 5
19 1 9 5
20 0 12 1
21 1 14 1
22 1 14 2
23 1 13 2
24 1 12 5
25 0 20 1
26 1 20 2
27 0 14 7
28 0 16 1
29 1 4 3
30 0 16 7
31 0 28 0
32 2 31 0
33 1 30 2
34 1 31 2
35 0 31 5
36 1 35 3
【样例输出】
11 9 10
【样例说明】
样例输入中37表示当前网络共有37台设备,19表示编号为19的计算机要打印文档。in.txt设备表中第一行0 0 -1 -1表示根节点交换机设备,其设备编号为0 、设备类型为0(交换机)、父结点设备编号-1表示无父设备、端口-1表示无接入端口;设备表第二行1 0 0 0表示设备编号为1 、设备类型为0(交换机)、父结点设备编号0(根交换机)、端口0表示接入父结点端口0;设备表中行5 1 4 0表示设备编号为5 、设备类型为1(计算机)、父结点设备编号4、端口0表示接入4号交换机端口0;设备表中行6 2 2 2表示设备编号为6 、设备类型为2(打印机)、父结点设备编号2、端口2表示接入2号交换机端口2。
样例输出11 9 10表示选择设备编号为11的打印机打印文档,打印需要经过9号和10号交换机(尽管6号和11号打印机离19号计算机距离相同,但11号打印机按树前序遍历时排在6号之前)。
【评分标准】
按题目要求实现相关功能,提交程序文件名为print.c。
采用的解法很暴力:
先dfs出所有的打印机节点,存储到一个数组里面;
然后遍历这个数组,分别求出最短路径,取最短的那条输入;
而对于计算最短路径的方法:
若要求节点p,q之间的最短路径,首先需要寻找他们的最深层公共祖先(要让pq联通,路径肯定是要过其公共祖先的,而求出最小的(最深层)的祖先,肯定是最短的)
而要求公共祖先,就抽象成了两个有序集合求交集的问题。最暴力的方法就是遍历一个集合,然后判断遍历到的元素是不是在另一个集合内,所以:从p开始,一层一层往上找其parent节点,若这个parent节点是q的祖先,则就找到了。
这时候我们已经走完了p到公共祖先的路程,接下来用ride2函数,从公共祖先走到q,只需要一个简单的dfs即可。注意路径长度使用递归返回值比用回溯来得方便。
最后按照和上面同样的方法,打印这条路径就好了。
代码如下(蹩脚英语注释又来辣)
#include <stdio.h>
#include <stdlib.h>
typedef struct node_type
{
int number;
int type;
int parent; //the number of it's parent
struct node_type *child[10];
} node; //node of tree
node *root;
node *search(node *p, int key)
{
if (p->number == key)
return p;
if (p->child[0] == NULL && p->child[1] == NULL && p->child[2] == NULL && p->child[3] == NULL && p->child[4] == NULL && p->child[5] == NULL && p->child[6] == NULL && p->child[7] == NULL)
return NULL;
for (int i = 0; i < 10; i++)
{
if (p->child[i] != NULL && search(p->child[i], key) != NULL)
return search(p->child[i], key);
}
return NULL;
} //search the node whose number is a given key, then return the address of this node
void pre_order(node *p)
{
printf("%d %d\n", p->number, p->type);
for (int i = 0; i < 10; i++)
{
if (p->child[i] != NULL)
pre_order(p->child[i]);
}
}
node *printer[1024];
int printer_num = 0;
void get_printer(node *p)
{
if (p->type == 2)
printer[printer_num++] = p;
for (int i = 0; i < 10; i++)
{
if (p->child[i] != NULL)
get_printer(p->child[i]);
}
} //to find all the printers, and record them in the array printer;
int is_ances(node *anc, node *p)
{
for (int i = 0; i < 10; i++)
{
if (anc->child[i] == p)
return 1;
if (anc->child[i] != NULL && is_ances(anc->child[i], p))
return 1;
}
return 0;
} //judge if anc is the ancestor of p
int ride2(node *t, node *q)
{
int len = 1;
for (int i = 0; i < 10; i++)
{ //search q:dfs
if (t->child[i] == q)
return len;
if (t->child[i] != NULL && is_ances(t->child[i], q))
return len + ride2(t->child[i], q);
}
return len;
} //in this function t is the ancestor of p,q u find in ride function
int ride(node *p, node *q)
{
node *t = search(root, p->parent);
int len = 1;
while (is_ances(t, q) == 0)
{ //to find the deepest shared ancestor of q and p,which names t
t = search(root, t->parent);
len++;
}
len += ride2(t, q); //the you need to find the way between t and q by function ride2
return len;
} //find the shortest ride between 1 p, q
/*these two functions are same as before,just need to print the number while you go along the ride*/
void show_ride2(node *t, node *q)
{
for (int i = 0; i < 10; i++)
{
if (t->child[i] == q)
{
printf("%d ", t->number);
return;
}
if (t->child[i] != NULL && is_ances(t->child[i], q))
{
printf("%d ", t->number);
show_ride2(t->child[i], q);
return;
}
}
}
void show_ride(node *p, node *q)
{
node *t = search(root, p->parent);
while (is_ances(t, q) == 0)
{
printf("%d ", t->number);
t = search(root, t->parent);
}
show_ride2(t, q);
}
int main()
{
root = (node *)malloc(sizeof(node));
int n;
scanf("%d", &n);
for (int i = 0; i < 10; i++)
root->child[i] = NULL;
FILE *in;
in = fopen("in.txt", "r");
while (n--)
{
int num;
int ty;
int par;
int k;
fscanf(in, "%d%d%d%d", &num, &ty, &par, &k);
if (par == -1)
{ //if it is root
root->number = num;
root->type = ty;
root->parent = 0;
}
else
{ //if is not root
node *t = search(root, par); //find it's parent and insert them
node *p = (node *)malloc(sizeof(node));
p->number = num;
p->type = ty;
p->parent = par;
for (int i = 0; i < 10; i++)
p->child[i] = NULL;
t->child[k] = p;
}
}
//pre_order(root);
int s;
scanf("%d", &s);
node *src = search(root, s);
get_printer(root); //get all the printers by pre order traverse
//for(int i=0;i<printer_num;i++) printf("%d ",printer[i]->number);
node *min_p = printer[0];
int min_way = ride(src, printer[0]);
for (int i = 0; i < printer_num; i++)
{
if (ride(src, printer[i]) < min_way)
{
min_way = ride(src, printer[i]);
min_p = printer[i];
}
} //find the shortest way
printf("%d ", min_p->number);
show_ride(src, min_p);
fclose(in);
}