PTA File Transfer 思路分析及代码解析

一、前导

1. 需要掌握的知识

  1. 并查集的基本概念

2. 题目信息

题目来源:PTA / 拼题A
题目地址:https://pintia.cn/problem-sets/16/problems/670

二、解题思路分析

1. 题意理解

已知有N部计算机,默认无网络连接。C n1 n2 表示检查两部计算机之间是否存在网络连接;I n1 n2 表示在两部计算机之间添加网络连接;举例:若n1 n2存在连接、n2 n4存在连接,则n1 n4之间可以传送文件,以此类推

1. 1 输入数据

5   \\'5' 代表网络中共有5台计算机,编号从1到5
C 3 2  \\检查 3#计算机 和 2#计算机 之间是否能够传送文件
I 3 2  \\在3#计算机 和 2#计算机 之间添加一根网线
C 1 5  \\检查 1# 和 5 #是否能够传送文件
I 4 5  \\ 在4#计算机 和 5#计算机 之间添加一根网线
I 2 4  \\ 在2#计算机 和 4#计算机 之间添加一根网线
C 3 5  \\检查 3# 和 5 #是否能够传送文件
S  \\结束,统计网络连接情况

1.2 输出数据

no  \\ 对应C 3 2,默认无网络连接,因此不能传送文件
no \\对应C 1 5,1# 和 5 #无网络连接,因此不能传送文件
yes \\对应C 3 5,因为此时 3# 2# 4# 5# 之间存在网络连接,所以可以传送文件
There are 2 components. \\ 1# 和 3# 2# 4# 5# ,共2个。若只有一个网络,输出 The network is connected.

1.3 补充

n1 若和其他计算机无网络连接,依据题意 n1也是一个单一的网络(孤岛),在最后的统计中需要单独计算

2. 思路分析(重点)

  1. 该题属于并查集的应用。并查集是树的一种形态:一父多子多孙。结合File Transfer这道题:(1)C n1 n2 对应并查集中的查(两点间网络是否连通):,只要n1 n2有相同的根节点,n1 n2必连通。(2)I n1 n2对应并查集中的并,将节点n1 n2并到相同的根节点下。代码只要正确实现 并 查 两个操作,就可以突破本题。

三、具体实现

1. 弯路和bug

  1. 通过Find()查询根节点时,使用while语句会更清晰容易
  2. 合并时,小树向大树合并,否则查找效率会越来越低(树偏向一边了)

2. 代码框架(重点)

2.1 采用的数据结构

本题通过一维数组来存储数据最方便:数组的下标对应计算机的编号,数组的值就是其其父节点所在位置。对于根节点,其数组值为 负数 ,数组值的绝对值就是树的元素值。所有节点初始都是根节点,数组值都是-1

void Init(int a[],int n)
{
   
	for(int i=0;i<n;i++)
		a[i]=root; //every Node is island , root=-1
}

2.2 程序主体框架

首先完成数据的初始化,然后通过switch语句根据关键字 C, I , S分别进行处理:C 对应并查集中的 查询,I 对应并查集中的 合并,S对应统计

               程序伪码描述
int main()
{
   	
	1.初始化数据
	2.Switch语句
	{
   
		C: find();
		I: merge();
		S: count();
	}
	return 0;
}

2.3 各分支函数

1.void Init(int a[],int n); 初始化函数,数组的下标对应计算机的编号,数组的值就是其其父节点所在位置,默认值均为-1:每个节点都是孤岛

void Init(int a[],int n)
{
   
	for(int i=0;i<n;i++)
		a[i]=root; //every Node is island , root=-1
}
  1. int Find(int a[],int x); 通过find()找到根节点,存储编号 与 实际编号差1,因此执行减1操作。初始化时如果从1开始,则没有该问题
int Find(int a[],int x)
{
   
	x--;
	while(a[x]>=0)
		x=a[x];
	return x;
} 

  1. void Check(int a[],int x,int y); 检查x,y 的根节点是否相同,若相同,则存在网络连接,调用find()找到根节点,然后比对
void Check(int a[],int x,int y)
{
   
	int root1,root2;
	root1=Find(a,x);
	root2=Find(a,y);
	if(root1==root2) cout<<"yes"<<endl;
	else cout<<"no"<<endl;
	return;
}
  1. void Merge(int a[],int x,int y); 对应I指令,本质就是并查集中的合并。在合并时,小树向大树合并、合并后统计树的元素个数并更新。小树向大树合并是为了尽量控制树的深度,也就是保持查找效率
void Merge(int a[],int x,int y) 
{
   
	int root1,root2;
	root1=Find(a,x);
	root2=Find(a,y);
	if(root1!=root2 && a[root1]<=a[root2] ) 
	{
   
		a[root2]=root1;
		a[root1]--;
	}
	else if(root1!=root2 && a[root1]>a[root2])
	{
   
		a[root1]=root2;
		a[root2]--;
	}
	return;
}
  1. void Count(int a[],int n); 统计结果,值为负数的节点都需要录入
void Count(int a[],int n)
{
Spring Boot 提供了对明文加密和解密的支持,通常通过集成第三方库如Spring Security、BCrypt或Jasypt等来实现。以下是基本流程: 1. **添加依赖**:在项目的`pom.xml`或`build.gradle`文件中引入相应的加密库依赖。 ```xml <!-- Maven --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Gradle --> implementation 'org.springframework.boot:spring-boot-starter-security' ``` 2. **配置密码管理器**:Spring Security允许您配置密码管理器,比如`PasswordEncoder`接口,用于处理密码加密存储。例如,可以使用内置的`BCryptPasswordEncoder`或自定义的`PasswordEncoder`实现。 ```java @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } ``` 3. **加密用户密码**:在保存用户信息到数据库之前,使用密码管理器将明文密码转换为哈希形式。 ```java User user = new User("username", "password"); String hashedPassword = passwordEncoder().encode(user.getPassword()); ``` 4. **验证登录**:从数据库获取用户的哈希密码后,用相同的密码管理器解密并比较。 ```java String inputPassword = user.getPassword(); boolean isCorrect = passwordEncoder().matches(inputPassword, hashedPassword); ``` 5. **使用外部工具**:对于更复杂的加密需求,如使用对称或非对称加密,你可以考虑使用专门的加密库,如Jasypt或Java Cryptography Extension (JCE)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值