File Transfer (25 分)

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.

题目分析:

这道题的题意是先给定电脑数n,如果输入C,代表查询两个电脑是否连通,如果输入I,则将两个电脑连通,输入S代表输入结束。最后输出连通的集合的情况,只有一个电脑也认为是一个集合。这是一道标准的并查集的题,这里要如果没有进行优化的话,就会有评测点超时。所以代码里在连通时用了按秩合并,并且在查询的时候同时进行了路径压缩。

代码如下:

#include <iostream>

using namespace std;

int a[10001];

void Union();
int Find(int n);
void IsConnect();
void PrintConnect(int n);

int main()
{
	int i, n;
	char c;

	cin >> n;
	for( i=1; i<=10000; i++) {   //将所有元素先初始为-1
		a[i] = -1;
	}
	do{
		//getchar();
		cin >> c;    //输入字符,进行判断,至少进行一次,所以用do-while
		switch(c) {
			case 'I':   //连接操作
				Union();
				break;
			case 'C':
				IsConnect();    //查询是否连接
				break;
			case 'S':    //结束,输出连通集合情况
				PrintConnect(n);
				break;
		}
	}while(c != 'S');

    return 0;
}

void Union()   //连接操作
{
	int n, m, root1, root2;
	cin >> n >> m;   //输入要连接的两个电脑

	root1 = Find(n);  //查询他们所属的集合
	root2 = Find(m);

	if(root1 != root2) {   //如果集合不同,放在同一个集合中,相同的话就不需要操作了
		if( root1 < root2 ) {   //看哪个集合的有的元素更多,-元素个数表示。
			a[root1] = a[root1] + a[root2];  //将元素个数加在一起。
			a[root2] = root1;   //将元素少的集合并在元素多的集合当中。
		} else {
			a[root2] = a[root1] + a[root2];
			a[root1] = root2;
		}
	}

}

int Find(int n)
{
	if( a[n] < 0 ) {    //小于0,说明是根节点,返回
		return n;
	} else
		return a[n] = Find(a[n]);   //这里递归操作,路径压缩。便于后续的查找。
}

void IsConnect()   //判断连通情况
{
	int n, m, root1, root2;

	cin >> n >> m;

	root1 = Find(n);
	root2 = Find(m);

	if( root1 == root2 ) {   //所属同一个集合
		cout << "yes" << endl;
	} else {
		cout << "no" << endl;
	}
}

void PrintConnect(int n)   //输出连通集情况
{
	int cnt = 0, i;

	for( i=1; i<=n; i++ ) {
		if( a[i] < 0 )
			cnt++;
	}

	if( cnt == 1 )   //cnt为1则全部连通
		cout << "The network is connected." << endl;
	else
		printf("There are %d components.\n", cnt);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值