24-2-1学习总结

新知学习

树 二叉树 堆 

目录

新知学习

树 二叉树 堆 

树的定义

 二叉树

 KMP算法(简单了解)

P3375 【模板】KMP

练习题 

Spreadsheets

Before an Exam

P2386 放苹果


树的定义

树是n(n>=0)个结点的有限集。当n = 0时,称为空树。在任意一棵非空树中应满足:

  1. 有且仅有一个特定的称为根的结点。
  2. 当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每个集合本身又是一棵树,并且称为根的子树。

显然,树的定义是递归的,即在树的定义中又用到了自身,树是一种递归的数据结构。树作为一种逻辑结构,同时也是一种分层结构,具有以下两个特点:

  1. 树的根结点没有前驱,除根结点外的所有结点有且只有一个前驱。
  2. 树中所有结点可以有零个或多个后继。

因此n个结点的树中有n-1条边。

借用一下吧,确实讲的不错,下面是原文链接

 

 二叉树

简单说就是一种特殊的树,二叉树的特点就是每个节点只有两个儿砸(左儿砸和右儿砸)

满二叉树的严格定义就是一颗深度为h且有2^{h}-1个节点的二叉树。

完全二叉树的严格定义是:若设二叉树的高度为h,除了第h层外,其他各层(1~h-1)的结点数都达到最大个数,第h层从右向左连续缺少若干结点,则这个二叉树就是完全二叉树。一个结点有右节点就一定有左节点。

堆是完全二叉树的典型应用。(主要是用于实现优先队列)

最大堆的建立与堆排序

//最大堆的建立与堆排序
int h[101] = { 0 };   //存放堆的数组
int n = 0;            //堆的大小
//交换函数
void swap(int x, int y)
{
	int t;
	t = h[x];
	h[x] = h[y];
	h[y] = t;
	return;
}
//向下调整函数
void siftdown(int i)
{
	int t, flag = 0;
	while (i * 2 <= n && flag == 0)
	{
		if (h[i] < h[i * 2])
			t = i * 2;
		else
			t = i;
		if (i * 2 + 1 <= n)
		{
			if (h[i] < h[i * 2 + 1])
				t = i * 2 + 1;
		}
		if (t != i)
		{
			swap(t, i);
			i = t;
		}
		else
			flag = 1;
	}
	return;
}
//建立堆的函数
void creat()
{
	for (int i = n / 2; i >= 1; i--)
	{
		siftdown(i);
	}
	return;
}
//堆排序
void heapsort()
{
	while (n > 1)
	{
		swap(1, n);
		n--;
		siftdown(1);
	}
	return;
}
int main()
{
	int num = 0;
	scanf("%d", &num);
	for (int i = 1; i <= num; i++)
	{
		scanf("%d", &h[i]);
	}
	n = num;
	creat();
	heapsort();
	for (int i = 1; i <= num; i++)
	{
		printf("%d ", h[i]);
	}
	return 0;
}
//14
//99 5 36 7 22 17 46 12 2 19 25 28 1 92

最小堆的建立与堆排序

//最小堆的建立与堆排序 
int h[101] = { 0 };
int n = 0;
//交换函数
void swap(int x, int y)
{
	int t;
	t = h[x];
	h[x] = h[y];
	h[y] = t;
	return;
}
//向下调整函数
void siftdown(int i)
{
	int t, flag = 0;
	while (i * 2 <= n && flag == 0)          //一直保持父节点小于叶节点(子节点)
	{
		//先判断和左儿子的大小关系
		if (h[i] > h[i * 2])
		{
			t = i * 2;
		}
		else
			t = i;
		//再判断和右节点的大小关系
		if (i * 2 + 1 <= n)
		{
			if (h[t] > h[i * 2 + 1])
				t = i * 2 + 1;
		}
		if (t != i)
		{
			swap(i, t);
			i = t;
		}
		else
			flag = 1;
	}
	return;

}
//建立堆函数
void creat()
{
	for (int i = n / 2; i >= 1; i--)
	{
		siftdown(i);
	}
	return;
}
//删除(弹出)最大的元素
int deletemax()
{
	int t;
	t = h[1];
	h[1] = h[n];  //把叶节点的数字提到前面来
	n--;
	siftdown(1);  //通过向下调整,来保证最小的数始终是根节点,然后弹出根节点
	return t;
}
int main()
{
	int num = 0;                //注意不能用n代替num   因为在弹出最小值的时候 n会减少
	scanf("%d", &num);
	for (int i = 1; i <= num; i++)
	{
		scanf("%d", &h[i]);
	}
	n = num;

	//建堆
	creat();

	//弹出最小值
	for (int i = 1; i <= num; i++)
	{
		printf("%d ", deletemax());
	}
	return 0;
}
//14
//99 5 36 7 22 17 46 12 2 19 25 28 1 92

 KMP算法(简单了解)

基本步骤

  1. 寻找前缀后缀最长公共元素长度
  2. 求next数组
  3. 根据next数组进行匹配

主要记录一下next数组的查找

//KMP
//构建next数组
void getNext(int* next, const char* s)
{
	int j = 0;
	next[0] = 0;
	for (int i = 1; i < strlen(s); i++)
	{
		while (j > 0 && s[i] != s[j])
			j = next[j - 1];
		if (s[i] == s[j])
			j++;
		next[i] = j;
	}
}

放一个例题吧

P3375 【模板】KMP

# 【模板】KMP

## 题目描述

给出两个字符串 $s_1$ 和 $s_2$,若 $s_1$ 的区间 $[l, r]$ 子串与 $s_2$ 完全相同,则称 $s_2$ 在 $s_1$ 中出现了,其出现位置为 $l$。  
现在请你求出 $s_2$ 在 $s_1$ 中所有出现的位置。

定义一个字符串 $s$ 的 border 为 $s$ 的一个**非 $s$ 本身**的子串 $t$,满足 $t$ 既是 $s$ 的前缀,又是 $s$ 的后缀。  
对于 $s_2$,你还需要求出对于其每个前缀 $s'$ 的最长 border $t'$ 的长度。

## 输入格式

第一行为一个字符串,即为 $s_1$。  
第二行为一个字符串,即为 $s_2$。

## 输出格式

首先输出若干行,每行一个整数,**按从小到大的顺序**输出 $s_2$ 在 $s_1$ 中出现的位置。  
最后一行输出 $|s_2|$ 个整数,第 $i$ 个整数表示 $s_2$ 的长度为 $i$ 的前缀的最长 border 长度。

## 样例 #1

### 样例输入 #1

```
ABABABC
ABA
```

### 样例输出 #1

```
1
3
0 0 1
```

## 提示

### 样例 1 解释

 ![](https://cdn.luogu.com.cn/upload/pic/2257.png)。
 
对于 $s_2$ 长度为 $3$ 的前缀 `ABA`,字符串 `A` 既是其后缀也是其前缀,且是最长的,因此最长 border 长度为 $1$。


### 数据规模与约定

**本题采用多测试点捆绑测试,共有 3 个子任务**。

- Subtask 1(30 points):$|s_1| \leq 15$,$|s_2| \leq 5$。
- Subtask 2(40 points):$|s_1| \leq 10^4$,$|s_2| \leq 10^2$。
- Subtask 3(30 points):无特殊约定。

对于全部的测试点,保证 $1 \leq |s_1|,|s_2| \leq 10^6$,$s_1, s_2$ 中均只含大写英文字母。

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<bits/stdc++.h>
#define MAXN 1000010
using namespace std;
int kmp[MAXN];
char a[MAXN], b[MAXN];
int main()
{
	int la = 0, lb = 0, j = 0;
	cin >> a + 1;
	cin >> b + 1;
	la = strlen(a + 1);
	lb = strlen(b + 1);
	for (int i = 2; i <= lb; i++)
	{
		while (j > 0 && b[i] != b[j + 1])
			j = kmp[j];
		if (b[j + 1] == b[i])
			j++;
		kmp[i] = j;
	}
	j = 0;
	for (int i = 1; i <= la; i++)
	{
		while (j > 0 && a[i] != b[j + 1])
			j = kmp[j];
		if (b[j + 1] == a[i])
			j++;
		if (j == lb)
		{
			cout << i - lb + 1 << endl;
			j = kmp[j];
		}
	}
	for (int i = 1; i <= lb; i++)
	{
		cout << kmp[i] << " ";
	}
	return 0;
}

练习题 

Spreadsheets

# Spreadsheets

## 题面翻译

人们常用的电子表格软件(比如: Excel)采用如下所述的坐标系统:

第一列被标为 A,第二列为 B,以此类推,第 $26$ 列为 Z。接下来为由两个字母构成的列号: 第 $27$ 列为 AA,第 $28$ 列为 AB $\cdots$ 在标为 ZZ 的列之后则由三个字母构成列号,如此类推。

行号为从 $1$ 开始的整数。

单元格的坐标由列号和行号连接而成。比如,BC23 表示位于第 $55$ 列 $23$ 行的单元格。

有时也会采用被称为 RXCY 的坐标系统,其中 $X$ 与 $Y$ 为整数,坐标 $(X$,$Y)$ 直接描述了对应单元格的位置。比如,R23C55 即为前面所述的单元格。

您的任务是编写一个程序,将所给的单元格坐标转换为另一种坐标系统下面的形式。

## 输入

第一行一个整数 $n$ $(1$ $\le$ $n$ $\le$ $10^5)$ 表示将会输入的坐标的数量。

接下来 $n$ 行,每行一个坐标。

注意: 每个坐标都是正确的。此外不会出现行号或列号大于 $10^6$ 的单元格。

输出 $n$ 行,每行一个被转换的坐标。

## 输出
$n$ 行,每行一个被转换的坐标。

## 题目描述

In the popular spreadsheets systems (for example, in Excel) the following numeration of columns is used. The first column has number A, the second — number B, etc. till column 26 that is marked by Z. Then there are two-letter numbers: column 27 has number AA, 28 — AB, column 52 is marked by AZ. After ZZ there follow three-letter numbers, etc.

The rows are marked by integer numbers starting with 1. The cell name is the concatenation of the column and the row numbers. For example, BC23 is the name for the cell that is in column 55, row 23.

Sometimes another numeration system is used: RXCY, where X and Y are integer numbers, showing the column and the row numbers respectfully. For instance, R23C55 is the cell from the previous example.

Your task is to write a program that reads the given sequence of cell coordinates and produce each item written according to the rules of another numeration system.

## 输入格式

The first line of the input contains integer number $ n $ ( $ 1<=n<=10^{5} $ ), the number of coordinates in the test. Then there follow $ n $ lines, each of them contains coordinates. All the coordinates are correct, there are no cells with the column and/or the row numbers larger than $ 10^{6} $ .

## 输出格式

Write $ n $ lines, each line should contain a cell coordinates in the other numeration system.

## 样例 #1

### 样例输入 #1

```
2
R23C55
BC23
```

### 样例输出 #1

```
BC23
R23C55
```

#include<bits/stdc++.h>
using namespace std;
char x[1000010];
int main()
{
	int n = 0, k = 0, j = 0;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		bool t = true;
		cin >> x;
		int len = strlen(x);
		if(x[0]=='R'&&x[1]>='1'&&x[1]<='9')
			for (int j = 2; j < len; j++)
			{
				if (x[j] == 'C')
				{
					k = j;
					t = false;
					break;
				}
			}
		if (t)
		{
			int a[10];
			int sum = 0, j = 0;
			while (x[j] >= 'A' && x[j] <= 'Z')
				j++, a[j] = x[j - 1] - 'A' + 1;
			int k = j;
			for (int i = 1; i <= j; i++)
			{
				int ans = 1;
				for (int k = 1; k <= j - i; k++)
					ans *= 26;
				sum += a[i] * ans;
			}
			cout << "R";
			j--;
			for (int i = j+1; i < len; i++)
			{
				cout << x[i];
			}
			cout << "C" << sum;
			cout << endl;
		}
		if (!t)
		{
			int a, b, x1[10];
			a = x[k + 1] - '0'; b = x[1] - '0';
			for (int i = k + 2; i < len; i++)
				a = a * 10 + x[i] - '0';
			for (int i = 2; i < k; i++)
				b = b * 10 + x[i] - '0';
			int sum = 0, sum1 = 0;
			int k = 0;
			while (a != 0)
			{
				k++;
				if (a % 26 != 0)x1[k] = a % 26, a /= 26;
				else x1[k] = 26, a = a / 26 - 1;

			}
			for (int i = k; i >= 1; i--)
			{
				cout << char(x1[i] + 'A' - 1);
			}
			cout << b;
			cout << endl;
		}
	}
	return 0;
}

Before an Exam

# Before an Exam

## 题面翻译

### 题目背景

明天皮特将要考生物。他并不很喜欢生物,但在 $d$ 天前他得知他将不得不参加此次考试。皮特严厉的父母勒令他立即复习,因此他在第 $i$ 天将需要学习不少于 $minTime_i$ 小时,不多于 $maxTime_i$ 小时。他们同时警告皮特:考试前一天,他将被检查他复习的完成情况。

因此,今天皮特的父母会要求他展示他考前复习的学习时间表。然而,他只记录这 $d$ 天以来他复习所用的总计用时 $sumTime$(小时).现在他希望知道他能否给他的父母展示一份时间表,包含 $d$ 个数,每个数 $schedule_i$ 表示皮特第 $i$ 天在复习生物上的用时(单位为小时),并应满足上文提及的要求。

### 题目输入

第一行包含两个数:$d,sumTime$。

$\left(1\le d\le30,0\le sumTime\le240\right)$,意义如上所述。

接下来 $d$ 行,每行两个数:$minTime_i,maxtime_i$,两个数之间有一个空格,意义如上。$\left(0\le minTime_i\le maxTime_i\le8\right)$

### 题目输出

如果有解,在单独一行输出 `YES`,换行,输出任意一种满足上文要求的解。如果无解,在单独一行中输出 `NO`。

Translated by @B_1168, @ivyjiao, @bye_wjx。

## 题目描述

Tomorrow Peter has a Biology exam. He does not like this subject much, but $ d $ days ago he learnt that he would have to take this exam. Peter's strict parents made him prepare for the exam immediately, for this purpose he has to study not less than $ minTime_{i} $ and not more than $ maxTime_{i} $ hours per each $ i $ -th day. Moreover, they warned Peter that a day before the exam they would check how he has followed their instructions.

So, today is the day when Peter's parents ask him to show the timetable of his preparatory studies. But the boy has counted only the sum of hours $ sumTime $ spent him on preparation, and now he wants to know if he can show his parents a timetable $ sсhedule $ with $ d $ numbers, where each number $ sсhedule_{i} $ stands for the time in hours spent by Peter each $ i $ -th day on biology studies, and satisfying the limitations imposed by his parents, and at the same time the sum total of all $ schedule_{i} $ should equal to $ sumTime $ .

## 输入格式

The first input line contains two integer numbers $ d,sumTime $ ( $ 1<=d<=30,0<=sumTime<=240 $ ) — the amount of days, during which Peter studied, and the total amount of hours, spent on preparation. Each of the following $ d $ lines contains two integer numbers $ minTime_{i},maxTime_{i} $ ( $ 0<=minTime_{i}<=maxTime_{i}<=8 $ ), separated by a space — minimum and maximum amount of hours that Peter could spent in the $ i $ -th day.

## 输出格式

In the first line print YES, and in the second line print $ d $ numbers (separated by a space), each of the numbers — amount of hours, spent by Peter on preparation in the corresponding day, if he followed his parents' instructions; or print NO in the unique line. If there are many solutions, print any of them.

## 样例 #1

### 样例输入 #1

```
1 48
5 7
```

### 样例输出 #1

```
NO
```

## 样例 #2

### 样例输入 #2

```
2 5
0 1
3 5
```

### 样例输出 #2

```
YES
1 4
```

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
int mins = 0, maxs = 0, i = 0, s = 0, n = 0;
int a[31] = { 0 }, b[31] = { 0 };
int main()
{
	cin >> n >> s;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i] >> b[i];
		mins += a[i];
		maxs += b[i];
	}
	if (s <= maxs && s >= mins)
	{
		cout << "YES" << endl;
		s -= mins;
		i = 1;
		while (s)
		{
			if (s > b[i] - a[i])
			{
				s -= b[i] - a[i];
				a[i] = b[i];
			}
			else
			{
				a[i] += s;
				s = 0;
			}
			i++;
		}
		for (int i = 1; i <= n; i++)
		{
			cout << a[i] << " ";
		}
	}
	else
		cout << "NO" << endl;
	return 0;
}

P2386 放苹果

# 放苹果

## 题目描述

把 $m$ 个同样的苹果放在 $n$ 个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法。($5,1,1$ 和 $1,1,5$ 是同一种方法)

## 输入格式

第一行是测试数据的数目 $t$,以下每行均包括二个整数 $m$ 和 $n$,以空格分开。

## 输出格式

对输入的每组数据 $m$ 和 $n$,用一行输出相应的结果。

## 样例 #1

### 样例输入 #1

```
1
7 3
```

### 样例输出 #1

```
8
```

## 样例 #2

### 样例输入 #2

```
3
3 2
4 3
2 7
```

### 样例输出 #2

```
2
4
2
```

## 提示

对于所有数据,保证:$1\leq m,n\leq 10$,$0 \leq t \leq 20$。

#include<bits/stdc++.h>
using namespace std;
int sum[1000];
int func(int m, int n)
{
	if (m == 0 || m == 1 || n == 1)
		return 1;
	else if (m < n)
		return func(m, m);
	else
		return func(m - n, n) + func(m, n - 1);
}
int main()
{
	int n = 0, m = 0, s = 0;
	cin >> s;
	for (int i = 0; i < s; i++)
	{
		cin >> m >> n;
		sum[i] = func(m, n);
	}
	for (int i = 0; i < s; i++)
	{
		cout << sum[i] << endl;
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值