全部每周作业和视频思考题答案和解析 见 浙江大学 数据结构 思考题+每周练习答案汇总
题目:We have a network of computers and a list of bi-directional connections. Each of these connections allows a file transfer from one computer to another. Is it possible to send a file from any computer on the network to any other?
Input Specification:
Each input file contains one test case. For each test case, the first line contains N (2≤N≤10^4), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 and N. Then in the following lines, the input is given in the format:
I c1 c2
where I
stands for inputting a connection between c1
and c2
; or
C c1 c2
where C
stands for checking if it is possible to transfer files between c1
and c2
; or
S
where S
stands for stopping this case.
Output Specification:
For each C
case, print in one line the word "yes" or "no" if it is possible or impossible to transfer files between c1
and c2
, respectively. At the end of each case, print in one line "The network is connected." if there is a path between any pair of computers; or "There are k
components." where k
is the number of connected components in this network.
Sample Input 1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
Sample Output 1:
no
no
yes
There are 2 components.
Sample Input 2:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S
Sample Output 2:
no
no
yes
yes
The network is connected.
解答:
题目不难,但是还是得细心。视频中介绍的很详细,这里只谈谈技巧。
调试中遇到的bug: 首先在我复制题目的时候10^4复制成了104,结果数组建小了,一直段错误,很长时间才查出来原因。
其次,在我检查的程序里:
int a = network[num1];
int b = num1;
while (a > 0) {
b = a;
a = network[a];
}
这个一开始写成了b = a,因为Input和Check里都有这一段,我只改了其中一个,导致程序结果错误。
在输入网络连接过程中有两种思路,我先放一个可以通过全部测试的程序:
#include <iostream>
using namespace std;
#define MaxSize 11000
int network[MaxSize];
void Input(int num1,int num2);
void Check(int num1, int num2);
void Test(int N);
void Print(int N);
int main(void) {
int N;
cin >> N;
for (int i = 0;i <= N;i++) {
network[i] = -1;
}
char op;
cin >> op;
int num1, num2;
while (op!='S') {
if (op == 'C')
{
cin >> num1 >> num2;
Check(num1, num2);
}
else {
cin >> num1 >> num2;
Input(num1, num2);
}
cin >> op;
}
Test(N);
system("pause");
return 0;
}
void Input(int num1, int num2) {
if (network[num1] < 0 && network[num2]<0) {
if (network[num1] < network[num2]) {
network[num1] += network[num2];
network[num2] = num1;
}
else {
network[num2] += network[num1];
network[num1] = num2;
}
}
else {
int a = network[num1];
int b = num1;
if (a < 0) {
}
else {
while (a > 0) {
b = a;
a = network[a];
}
//b 是索引为-的坐标
}
int c = network[num2];
int d = num2;
if (c < 0) {
}
else {
while (c > 0) {
d = c;
c = network[c];
}
//d 是索引为-的坐标
}
if (network[b] <= network[d]) {
network[b] += network[d];
network[d] = b;
}
else {
network[d] += network[b];
network[b] = d;
}
}
}
//
void Check(int num1, int num2) {
int a = network[num1];
int b = num1;
while (a > 0) {
b = a;
a = network[a];
}
//b 是索引为-的坐标
int c = network[num2];
int d = num2;
while (c > 0) {
d = c;
c = network[c];
}
if (b == d && b > 0) {
cout << "yes" << endl;
}
else {
cout << "no" << endl;
}
}
void Test(int N) {
int num = 0;
for (int i = 1;i <= N;i++) {
if (network[i] < 0) {
num++;
}
}
if (num == 1)cout << "The network is connected.";
else cout << "There are " << num << " components.";
}
void Print(int N) { //测试连接效果用
for (int i = 1;i <= N;i++) {
cout << network[i] << " ";
}
cout << endl;
}
然后结果:
进行连接之前首先要找到每个的根节点,然后把根节点进行连接即可。寻找根节点的方法这里采用遍历,但是其实递归也是可以的:
int FindRoot(int num){
if(network[num] < 0){
return num;
}
else {
return network[num] = Find(network[num]);
//这样正如视频里提到过的,把递归中,递归路径上所有的点的父节点都指向根节点
}
}
这里递归的好处是可以把递归路径上所有的点的父节点都指向根节点,让树更小。
而且在后面合并中会比较容易,不用像上面那样还得一大堆if-else进行判断。
即,先求出两个的根节点索引,然后直接判断索引的大小,因为这个时候都是根节点,所以可以直接合并。
但是其实上面的程序多写了一些内容,完全不必要,其实大家应该能看出来,把最层的if-else去掉就行了:
void Input(int num1, int num2) {
int a = network[num1];
int b = num1;
if (a < 0) {
}
else {
while (a > 0) {
b = a;
a = network[a];
}
//b 是索引为-的坐标
}
int c = network[num2];
int d = num2;
if (c < 0) {
}
else {
while (c > 0) {
d = c;
c = network[c];
}
//d 是索引为-的坐标
}
if (network[b] <= network[d]) {
network[b] += network[d];
network[d] = b;
}
else {
network[d] += network[b];
network[b] = d;
}
}
所以读者可以继续进行修改。这里一开始放的比较冗杂的程序的意义是为了更好理解程序的思想。但其实一开始就是根节点和一开始不是根节点需要向上查找都可以同样进行考虑。