公式:对于 T ( n ) = a × T ( n b ) + O ( n d ) T(n) = a \times T(\dfrac{n}{b})+O(n^d) T(n)=a×T(bn)+O(nd) 这个递推式,其时间复杂度为:
T ( n ) = { O ( n log b a ) , a > b d O ( n d lg n ) , a = b d O ( n d ) , a < b d T(n) = \begin{cases} O(n^{\log_b a}) , \ a > b^d \\ \\ O(n^d \lg n) , \ a = b^d \\ \\ O(n^d) , \ aT(n)=⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧O(nlogba), a>bdO(ndlgn), a=bdO(nd), a<bd
算法 | 最大时间复杂度 | 平均时间复杂度 | 稳定性 | 分类 |
---|---|---|---|---|
直接插入排序 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | 稳定 | 插入排序 |
希尔排序 | O ( n 3 2 ) O(\dfrac{n^3}{2}) O(2n3) | O ( n 3 2 ) O(\dfrac{n^3}{2}) O(2n3) | 不稳定 | 插入排序 |
冒泡排序 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | 稳定 | 交换排序 |
快速排序 | O ( n 2 ) O(n^2) O(n2) | O ( n log n ) O(n \log n) O(nlogn) | 不稳定 | 交换排序 |
直接选择排序 | O ( n 2 ) O(n^2) O(n2) | O ( n 2 ) O(n^2) O(n2) | 不稳定 | 选择排序 |
堆排序 | O ( n log n ) O(n \log n) O(nlogn) | O ( n log n ) O(n \log n) O(nlogn) | 不稳定 | 选择排序 |
归并排序 | O ( n log n ) O(n \log n) O(nlogn) | O ( n log n ) O(n \log n) O(nlogn) | 稳定 | 选择排序 |
基数排序 | O ( d ( n + r ) ) O(d(n+r)) O(d(n+r)) | O ( d ( n + r ) ) O(d(n+r)) O(d(n+r)) | 稳定 | 选择排序 |
直接插入排序
定义:将一个记录插入到已排好序的有序表中,从而得到一个新的有序表。
希尔排序
定义:
Shell排序有效地利用了直接插入排序的两个性质: 在最好情况(序列本身已是有序的)下时间代价为Θ(n) ;对于短序列,直接插入排序比较有效:
- 先将序列转化为若干小序列,在这些小序列内进行插入排序。
- 逐渐扩大小序列的规模,而减少小序列个数,使得待排序序列逐渐处于更有序的状态。
- 最后对整个序列进行扫尾直接插入排序,从而完成排序。
冒泡排序
定义:不停地比较相邻的记录,如果不满足排序要求,就交换相邻记录,直到所有的记录都已经排好序。
注意:避免不必要的比较。检查每次冒泡过程中是否发生过交换,如果没有,则表明整个数组已经排好序了,排序结束。
快速排序
定义:
- 选择轴值(pivot)。
- 将序列划分为两个子序列L和R,使得L中所有记录都小于或等于轴值,R中记录都大于轴值。
- 对子序列L和R递归进行快速排序。
直接选择排序
选出剩下的未排序记录中的最小记录,然后直接与数组中第i个记录交换
堆排序
基于最大值堆来实现
归并排序
简单地将原始序列划分为两个子序列,并分别对每个子序列递归排序;
最后将排好序的子序列合并为一个有序序列,即归并过程。
- 归并排序可以求逆序对
基数排序
假设长度为 n n n 的序列 R = { r 0 , r 1 , … , r n − 1 } R=\{ r_0,r_1,…,r_n-1 \} R={r0,r1,…,rn−1}
记录的排序码 K K K 包含 d d d 个子排序码 K = ( k d − 1 , k d − 2 , … , k 1 , k 0 ) K=(k_d-1,k_d-2,…,k_1,k_0 ) K=(kd−1,kd−2,…,k1,k0)
R R R 对排序码 ( k d − 1 , k d − 2 , … , k 1 , k 0 ) (k_d-1,k_d-2,…,k_1,k_0 ) (kd−1,kd−2,…,k1,k0) 有序
对于任意两个记录 R i , R j ( 0 ≤ i < j ≤ n − 1 ) R i,R j (0 ≤ i< j ≤ n-1) Ri,Rj(0≤i<j≤n−1),都满足 ( k i , d − 1 , k i , d − 2 , … , k i , 1 , k i , 0 ) (k i ,d-1,k i ,d-2, …,k i ,1,k i,0 ) (ki,d−1,ki,d−2,…,ki,1,ki,0) $≤ $ ( k j , d − 1 , k j , d − 2 , … , k j , 1 , k j , 0 ) (k j ,d-1,k j, d-2,…,k j,1,k j,0 ) (kj,d−1,kj,d−2,…,kj,1,kj,0) 其中 k d − 1 k d-1 kd−1称为最高排序码 k 0 k 0 k0 称为最低排序码
- 基数排序分为两类:高位优先法 M S D MSD MSD,低位优先法 L S D LSD LSD
图论(英语:Graph theory)是组合数学的一个分支。图是图论的主要研究对象。图是由若干给定的顶点及连接两顶点的边所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系。顶点用于代表事物,连接两顶点的边则用于表示两个事物间具有这种关系。
图论起源于著名的柯尼斯堡七桥问题。该问题于 1736 1736 1736 年被欧拉解决,因此普遍认为欧拉是图论的创始人。
图(Graph)用于表示物件与物件之间的关系,是图论的基本研究对象。一张图由一些小圆点(称为顶点或结点)和连结这些圆点的直线或曲线(称为边)组成。
一张图 G G G 是一个二元组 ( V , E ) (V, E) (V,E),其中 V V V 称为顶点集, E E E 称为边集。它们亦可写成 V ( G ) V(G) V(G) 和 E ( G ) E(G) E(G)。 E E E 的元素是一个二元组数对,用 ( x , y ) (x,y) (x,y) 表示,其中 x , y ∈ V x, y \in V x,y∈V。
如果给图的每条边规定一个方向,那么得到的图称为有向图,其边也称为有向边。在有向图中,与一个节点相关联的边有出边和入边之分,而与一个有向边关联的两个点也有始点和终点之分。相反,边没有方向的图称为无向图。
一个图如果被称为简单图(Simple graph),那么:
度(Degree):一个顶点的度是指与该顶点相关联的总边数,顶点 v v v 的度记作 d ( v ) d(v) d(v)。度和边有如下关系: ∑ v ∈ V d ( v ) = 2 ∣ E ∣ \sum_{v \in V} d(v) = 2|E| ∑v∈Vd(v)=2∣E∣。
出度(Out-degree)和入度(In-degree):对有向图而言,顶点的度还可分为出度和入度。一个顶点的出度为 d o d_o do,是指有 d o d_o do 条边以该顶点为起点,或说与该点关联的出边共有 d o d_o do 条。入度的概念也类似。
子图(Sub-Graph):图 H H H 称作图 G G G 的子图如果 V ( H ) ⊆ V ( G ) V(H) \subseteq V(G) V(H)⊆V(G) 以及 E ( H ) ⊆ E ( G ) E(H) \subseteq E(G) E(H)⊆E(G)。
如果图 G G G 的子图 H H H,满足 V ( H ) = V ( G ) V(H) = V(G) V(H)=V(G),即图 H H H 包含图 G G G 的所有顶点,则称 H H H 是 G G G 的生成子图。特别的如果子图 H H H 是树,则称子图 H H H 为生成树。
如果图 G G G 的子图 H H H,满足对于 u , v ∈ V ( H ) u,v \in V(H) u,v∈V(H),边 ( u , v ) (u,v) (u,v) 在图 H H H 中当且仅当边 ( u , v ) (u,v) (u,v) 在图 G G G 中,即图 H H H 包含了图 G G G 中所有两个端点都在 V ( H ) V(H) V(H) 中的边,则称 H H H 是 G G G 的导出子图。
一个图 G G G 的补图(complement)是一个图有着跟 G G G 相同的点,而且这些点之间有边相连当且仅当在 G G G 里面他们没有边相连。
完全图是所有顶点两两相邻的图。 n n n 阶完全图,记作 K n K_n Kn。 n n n 阶完全图有 n ( n − 1 ) 2 \dfrac{n(n-1)}{2} 2n(n−1) 条边。
独立集(independent set)是图论中的概念。一个独立集是一个图中一些两两不相邻的顶点的集合。换句话说它是一个由顶点组成的集合 SS,使得 SS 中任两个顶点之间没有边。等价地,图中的每条边至多有一个端点属于SS。
二分图指顶点可以分成两个不相交的集 UU 和 VV,使得在同一个集内的顶点不相邻(没有共同边)的图,即UU和VV皆为独立集。
完全二分图是一种特殊的二分图,可以把图中的顶点分成两个集合 X , Y X,Y X,Y,使得集合 X X X 中的所有顶点都与集合 Y Y Y 中的所有顶点相连。若 ∣ X ∣ = m , ∣ Y ∣ = n |X| = m, |Y| = n ∣X∣=m,∣Y∣=n 则图 G G G 计作 K m , n K_{m, n} Km,n。
平面图是可以画在平面上并且使得不同的边可以互不交叠的图。而如果一个图无论怎样都无法画在平面上,并使得不同的边互不交叠,那么这样的图不是平面图,或者称为非平面图。
图论中有很多经典的NP完全问题
如果在做题中遇到类似问题,说明
Kruskal
。这个方法的缺点是,确定起点,不能很快的得到所有相邻的边。vector
,变长数组存。如果数据范围不大,或者评测打开O2
,vector
是非常方便的数据结构。若有 n n n 个鸽巢, n + 1 n+1 n+1 只鸽子,则至少有一个鸽巢里至少有两只鸽子。
变形:
( N O I P 2012 NOIP \ 2012 NOIP 2012 )如果平面上任取 n n n 个整点(横纵坐标都是整数),其中一定存在 2 2 2 个点,它们连线的中点也是整点,那么 n n n 至少是( )。
解: 存在 2 2 2 个点中点是整点,要求两点横纵坐标奇偶性都相同。根据鸽巢原理, n n n 至少是 2 × 2 + 1 = 5 2 \times 2+1=5 2×2+1=5
在边长为 1 1 1 的正方形内任取 5 5 5 点,则其中至少有 2 2 2 点的距离不超过( )。
解: 如下图所示,将一个正方形分成四份,那么至少有 2 2 2 个点在同一个小正方形里面。在同一个正方形里面的两点最长距离即为 2 2 \dfrac{\sqrt{2}}{2} 22 。
证明:一位国际象棋大师有 11 11 11 周的时间备战比赛,他决定每天至少下 1 1 1 盘棋,但每周不超过 12 12 12 盘。则存在连续若干天,他恰好下了 21 21 21 盘棋。
解: 令 a i a_i ai 为到第 i i i 天下的总盘数,那我们要证明存在 i , j i,j i,j 满足 a i + 21 = a j a_i+21=a_j ai+21=aj 。
∵ \because ∵ 他每天至少下 1 1 1 盘棋
∴ \therefore ∴ a i a_i ai 是单调递增的
∴ \therefore ∴ 1 < a 1 < a 2 < … < a 77 < 11 × 12 = 132 1 < a_1 < a_2 < \ldots < a_{77} < 11 \times 12=132 1<a1<a2<…<a77<11×12=132
∴ \therefore ∴ 22 < a 1 + 21 < a 2 + 21 < … < a 77 + 21 < 132 + 21 = 153 22 < a_1+21 < a_2+21 < \ldots < a_{77}+21 < 132+21=153 22<a1+21<a2+21<…<a77+21<132+21=153
上下两式总共有 153 153 153 种取值,却有 154 154 154 个数,所以存在 i < j i < j i<j 满足 a i + 21 = a j a_i+21=a_j ai+21=aj。
现有鸽巢 n n n 个,鸽子 m 1 + m 2 + ⋯ + m n − n + 1 m_1+m_2+ \cdots +m_n-n+1 m1+m2+⋯+mn−n+1 只,其中 m 1 , m 2 , … , m n , n ∈ N ∗ m_1,m_2, \ldots ,m_n, n \in \N^* m1,m2,…,mn,n∈N∗
结论: 鸽巢 1 1 1 鸽子数 > m 1 > m_1 >m1,或鸽巢 2 2 2 鸽子数 > m 2 > m_2 >m2,…… 或鸽巢 n n n 鸽子数 > m n > m_n >mn,至少有一个成立。
在由 n 2 + 1 n^2+1 n2+1 个实数构成的序列中,必然含有长为 n + 1 n+1 n+1 的单调(增或减)子序列。
命题: 6 6 6 人中或者至少存在 3 3 3 人互相认识,或者至少存在 3 3 3 人互相不认识。
等价问题:六个顶点的完全图的边,用红、蓝二色任意着色,则至少存在一红色边三角形,或一蓝色边三角形。
具体例题:
NOIP2012-20
A n n = n ! A_n^n = n! Ann=n!
A n m = n ( n − 1 ) ( n − 2 ) ⋯ ( n − m + 1 ) = n ! ( n − m ) ! A_n^m = n(n-1)(n-2) \cdots (n-m+1) = \dfrac{n!}{(n-m)!} Anm=n(n−1)(n−2)⋯(n−m+1)=(n−m)!n!
C n m = A n m A m m = n ( n − 1 ) ( n − 2 ) ⋯ ( n − m + 1 ) m ! = n ! m ! ( n − m ) ! C_n^m = \dfrac{A_n^m}{A_m^m} = \dfrac{n(n-1)(n-2) \cdots (n-m+1)}{m!} = \dfrac{n!}{m!(n-m)!} Cnm=AmmAnm=m!n(n−1)(n−2)⋯(n−m+1)=m!(n−m)!n!
另外,规定 C n 0 = 1 C_n^0 = 1 Cn0=1
圆排列(在一个圆里,经旋转后相同算同一种解): Q n r = A n r r = n ! r ⋅ ( n − r ) ! Q_n^r = \dfrac{A_n^r}{r} = \dfrac{n!}{r \cdot (n-r)!} Qnr=rAnr=r⋅(n−r)!n!
C n m = C n n − m \ C_n^m = C_n^{n-m} Cnm=Cnn−m
我们可以这么想:组合就是从 n n n 个元素中随机抽出 m m m 个元素,那这样和从 n n n 个元素中抽出 n − m n-m n−m 个元素保留不是一个道理吗?所以就有了这个公式: C n m = C n n − m \ C_n^m = C_n^{n-m} Cnm=Cnn−m
C n + 1 m = C n m + C n m − 1 C_{n+1}^m = C_n^m + C_n^{m-1} Cn+1m=Cnm+Cnm−1 【记牢,经常用!!!】
方法1:我们可以这么想:假设集合 A A A 中现在有 n + 1 n+1 n+1 个元素,分别为 a 1 , a 2 , ⋯ , a n + 1 a_1,a_2,\cdots,a_{n+1} a1,a2,⋯,an+1 ,那么从集合 A A A 中抽出 m m m 个元素,就可以分类讨论:如果抽出的元素中不含有 a 1 a_1 a1 ,那么就是从 n n n 个元素中抽出 m m m 个元素,一共有 C n m C_n^m Cnm 种;如果抽出的元素中含有 a 1 a_1 a1,那么就有 C n m − 1 C_n^{m-1} Cnm−1 种方法。所以 C n + 1 m = C n m + C n m − 1 C_{n+1}^m = C_n^m + C_n^{m-1} Cn+1m=Cnm+Cnm−1。
方法2:阶乘证明:
∵ \because ∵ 左边 = = = ( n + 1 ) ! m ! ( n + 1 − m ) ! \dfrac{(n+1)!}{m!(n+1-m)!} m!(n+1−m)!(n+1)!
∵ \because ∵ 右边 = = = n ! m ! ( n − m ) ! + n ! ( m − 1 ) ! ( n + 1 − m ) ! = n ! ( n − m + 1 ) m ! ( n + 1 − m ) ! + n ! ⋅ m m ! ( n + 1 − m ) ! = ( n + 1 ) ! m ! ( n + 1 − m ) ! \dfrac{n!}{m!(n-m)!} + \dfrac{n!}{(m-1)!(n+1-m)!} = \dfrac{n!(n-m+1)}{m!(n+1-m)!} + \dfrac{n! \cdot m}{m!(n+1-m)!} = \dfrac{(n+1)!}{m!(n+1-m)!} m!(n−m)!n!+(m−1)!(n+1−m)!n!=m!(n+1−m)!n!(n−m+1)+m!(n+1−m)!n!⋅m=m!(n+1−m)!(n+1)!
∴ \therefore ∴ 左边 = = = 右边
∴ C n + 1 m = C n m + C n m − 1 \therefore \ C_{n+1}^m = C_n^m + C_n^{m-1} ∴ Cn+1m=Cnm+Cnm−1
方法3:杨辉三角形的任意一个数都等于它肩上的两个数之和,再结合二项式定理,就可以得出这个规律。
C n m = m + 1 n + 1 C n + 1 m + 1 C_n^m = \dfrac{m+1}{n+1} C_{n+1}^{m+1} Cnm=n+1m+1Cn+1m+1
同样,这里也可以用阶乘来证明:
∵ \because ∵ 左边 = = = n ! m ! ( n − m ) ! \dfrac{n!}{m!(n-m)!} m!(n−m)!n!
∵ \because ∵ 右边 = = = m + 1 n + 1 ⋅ ( n + 1 ) ! ( m + 1 ) ! ( n + 1 − m − 1 ) ! = m + 1 n + 1 ⋅ ( n + 1 ) ! ( m + 1 ) ! ( n − m ) ! = m + 1 n + 1 ⋅ n ! ( n + 1 ) m ! ( n − m ) ! ( m + 1 ) = n ! m ! ( n − m ) ! \dfrac{m+1}{n+1} \cdot \dfrac{(n+1)!}{(m+1)!(n+1-m-1)!} = \dfrac{m+1}{n+1} \cdot \dfrac{(n+1)!}{(m+1)!(n-m)!} = \dfrac{m+1}{n+1} \cdot \dfrac{n! (n+1)}{m!(n-m)!(m+1)} = \dfrac{n!}{m!(n-m)!} n+1m+1⋅(m+1)!(n+1−m−1)!(n+1)!=n+1m+1⋅(m+1)!(n−m)!(n+1)!=n+1m+1⋅m!(n−m)!(m+1)n!(n+1)=m!(n−m)!n!
∴ \therefore ∴ 左边 = = = 右边
∴ \therefore ∴ C n m = m + 1 n + 1 C n + 1 m + 1 C_n^m = \dfrac{m+1}{n+1} C_{n+1}^{m+1} Cnm=n+1m+1Cn+1m+1
一个含有 n ( n ∈ N ∗ ) n \ (n \in N^*) n (n∈N∗) 个元素的集合 A = { a 1 , a 2 , ⋯ , a n } A = \{ a_1,a_2,\cdots , a_n \} A={a1,a2,⋯,an},不同的子集又 2 n 2^n 2n 个。
俗话来说,就是杨辉三角形!
二项式定理公式:
( a + b ) n = C n 0 a n + C n 1 a n − 1 b 1 + ⋯ + C n k a n − k b k + ⋯ + C n n b n ( n ∈ N ∗ ) \large (a+b)^n = C_n^0a^n + C_n^1a^{n-1}b^1 + \cdots + C_n^ka^{n-k}b^k + \cdots +C_n^nb^n (n \in N^*) (a+b)n=Cn0an+Cn1an−1b1+⋯+Cnkan−kbk+⋯+Cnnbn(n∈N∗)
二项式定理通项:
T k + 1 = C n k a n − k b k \large T_{k+1} = C_n^ka^{n-k}b^k Tk+1=Cnkan−kbk
二项式系数之和:
令 ( a + b ) n = C n 0 a n + C n 1 a n − 1 b 1 + ⋯ + C n k a n − k b k + ⋯ + C n n b n ( n ∈ N ∗ ) (a+b)^n = C_n^0a^n + C_n^1a^{n-1}b^1 + \cdots + C_n^ka^{n-k}b^k + \cdots +C_n^nb^n (n \in N^*) (a+b)n=Cn0an+Cn1an−1b1+⋯+Cnkan−kbk+⋯+Cnnbn(n∈N∗),那么 C n 0 + C n 1 + ⋯ + C n n = 2 n C_n^0 + C_n^1 + \cdots + C_n^n = 2^n Cn0+Cn1+⋯+Cnn=2n
证明:
用赋值法,令 a = b = 1 a = b = 1 a=b=1,那么 ( a + b ) n = C n 0 + C n 1 + ⋯ + C n n = ( 1 + 1 ) n = 2 n (a+b)^n = C_n^0 + C_n^1 + \cdots + C_n^n = (1+1)^n = 2^n (a+b)n=Cn0+Cn1+⋯+Cnn=(1+1)n=2n
二项式系数最值问题:
都知道杨辉三角形其实是一个十分对称的三角形,每一行的最大值就是在这一行最中间的那个数。对于 ( a + b ) n (a+b)^n (a+b)n,展开后只要关注 n 2 \dfrac{n}{2} 2n 的值。如果 n 2 \dfrac{n}{2} 2n 的值是整数,那么二项式系数的最大值就是 C n n 2 C_n^{\frac{n}{2}} Cn2n ;反之,如果 n 2 \dfrac{n}{2} 2n 是小数,那么二项式系数的最大值就是 C n [ n 2 ] , C n [ n 2 ] + 1 C_n^{[\frac{n}{2}]} , C_n^{[\frac{n}{2}]+1} Cn[2n],Cn[2n]+1 ( [ x ] [x] [x] 表示对 x x x 向下取整)。
问题:有 n n n 个信封和 n n n 个信箱,分别编号为 1 1 1 到 n n n,相同编号的信封和信箱不能放一起,则有几种方法?
公式: f ( n ) = ( n − 1 ) ( f ( n − 1 ) + f ( n − 2 ) ) f(n)=(n-1)(f(n-1)+f(n-2)) f(n)=(n−1)(f(n−1)+f(n−2))
错位排列的前几项: 0 , 1 , 2 , 9 , 44 , 265 0,1,2,9,44,265 0,1,2,9,44,265
并不是所有的问题都适用排列组合,视情况而定!
先看这个问题:在 n × n n \times n n×n 的网格里从左下角走到右上角的不经过 y = x y = x y=x 这条线的单调路径的条数。
路径条数即为: ( n 2 n ) − ( n − 1 2 n ) = 1 n + 1 ( n 2 n ) \dbinom{n}{2n} - \dbinom{n-1}{2n} = \dfrac{1}{n+1} \dbinom{n}{2n} (2nn)−(2nn−1)=n+11(2nn)
卡特兰数通式即为: C n = ( n 2 n ) − ( n − 1 2 n ) = 1 n + 1 ( n 2 n ) C_n = \dbinom{n}{2n} - \dbinom{n-1}{2n} = \dfrac{1}{n+1} \dbinom{n}{2n} Cn=(2nn)−(2nn−1)=n+11(2nn)
卡特兰数的递推公式 1 1 1: C n = C 0 × C n − 1 + C 1 × C n − 2 + ⋯ + C n − 1 × C 0 , C 0 = 1 C_n = C_0 \times C_{n-1} + C_1 \times C_{n-2} + \cdots + C_{n-1} \times C_0,C_0 = 1 Cn=C0×Cn−1+C1×Cn−2+⋯+Cn−1×C0,C0=1
卡特兰数的递推公式 2 2 2: C n = C n − 1 × ( 4 × n − 2 ) n + 1 C_n = \dfrac{C_{n-1} \times (4 \times n - 2)}{n+1} Cn=n+1Cn−1×(4×n−2)
求带限制条件的路径条数
求合法的括号序列的个数
求出栈次序
买票找票问题:有 2 n 2n 2n 个人排成一行进入剧场。入场费 5 5 5 元。其中只有 n n n 个人有一张 5 5 5 元钞票,另外 n n n 人只有 10 10 10 元钞票,剧院无其它钞票,问有多少种方法使得只要有 10 10 10 元的人买票,售票处就有 5 5 5 元的钞票找零?(将持 5 5 5 元者到达视作将 5 5 5 元入栈,持 10 10 10 元者到达视作使栈中某 5 5 5 元出栈)
排队问题:现在有 2 n 2n 2n 个人,他们身高互不相同,他们要成两排,每一排有 n n n 个人,并且满足每一排必须是从矮到高,且后一排的人要比前一排对应的人要高,问有多少种方案。
凸多边形三角划分:在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是输入凸多边形的边数 n n n,求不同划分的方案数 f ( n ) f(n) f(n)。
给定节点构成二叉搜索树
C语言里,变量存放在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址。CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位。这里,数据对象是指存储在内存中的一个指定数据类型的数值或字符串,它们都有一个自己的地址,而指针便是保存这个地址的变量。也就是说:指针是一种保存变量地址的变量。
指针其实就是一个变量,指针的声明方式与一般的变量声明方式没太大区别,下面举了几个栗子:
int *p; // 声明一个 int 类型的指针 p
char *p // 声明一个 char 类型的指针 p
int *arr[10] // 声明一个指针数组,该数组有10个元素,其中每个元素都是一个指向 int 类型对象的指针
int (*arr)[10] // 声明一个数组指针,该指针指向一个 int 类型的一维数组
int **p; // 声明一个指针 p ,该指针指向一个 int 类型的指针
声明一个指针变量并不会自动分配任何内存。在对指针进行间接访问之前,指针必须进行初始化:或是使他指向现有的内存,或者给他动态分配内存,否则我们并不知道指针指向哪儿。同时,对指针进行初始化后,便可以正常对指针进行赋值了。 初始化的操作如下:
/* 方法:使指针指向现有的内存 */
int x = 1;
int *p = &x; // 指针 p 被初始化,指向变量 x ,其中取地址符 & 用于产生操作数内存地址
就如下面这个程序,输出为:1 2
#include
int main(){
int x = 1;
int *p = &x;
printf("%d ",*p);
*p = 2;
printf("%d\n",*p);
return 0;
}
NULL 指针是一个特殊的指针变量,表示不指向任何东西。可以通过给一个指针赋一个零值来生成一个 NULL 指针。
指针 + / − +/- +/− 整数
可以对指针变量 p p p 进行 p++
、p--
、p+i
等操作,所得结果也是一个指针,只是指针所指向的内存地址相比于 p p p 所指的内存地址前进或者后退了 i i i 个操作数。
指针 − - − 指针
只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位),因为减法运算的结果将除以数组元素类型的长度。举个例子:
#include "stdio.h"
int main(){
int a[10] = {1,2,3,4,5,6,7,8,9,0};
int sub;
int *p1 = &a[2];
int *p2 = &a[8];
sub = p2-p1;
printf("%d\n",sub); // 输出结果为 6
return 0;
}
概念:非:not ¬ ¬ ¬ 与:and ∧ ∧ ∧ 或:or ∨ ∨ ∨ 异或:xor ⊕ ⊕ ⊕
运算符的优先级:
NOI
全国青少年信息学奥林匹克竞赛,从 1984 1984 1984 年开始至今NOIP
全国青少年信息学奥林匹克联赛,从 1995 1995 1995 年到 2018 2018 2018 年(NOIP已死)CSP认证
从 2014 2014 2014 年开始CSP-J/S
非专业级别的能力认证,从 2019 2019 2019 年开始APIO
亚洲与太平洋地区信息学奥赛,从 2007 2007 2007 年开始,第一届在澳大利亚举行IOI
国际信息学奥林匹克竞赛,从 1989 1989 1989 年在保加利亚开始。中国承办 IOI 2000
不用说了,自己访问 www.noi.cn 去看吧!
1946 1946 1946 年 2 2 2 月,在美国宾夕法尼亚大学诞生了世界上第一台电子计算机ENIAC
,这台计算机占地 170 170 170 平方米,重 30 30 30 吨,用了 18000 18000 18000 多个电子管,每秒能进行 5000 5000 5000 次加法运算。
计算机的 4 4 4 个发展过程:
1. 1. 1. 电子管 1946 − 1958 1946 - 1958 1946−1958
2. 2. 2. 晶体管 1959 − 1964 1959-1964 1959−1964
3. 3. 3. 集成电路 1965 − 1970 1965-1970 1965−1970
4. 4. 4. 大规模,超大规模集成电路 1971 − N o w 1971 - Now 1971−Now
冯·诺依曼(美籍匈牙利数学家)思想:计算机由存储器,控制器,运算器,输入设备,输出设备 5 5 5 部分组成。
图灵:英国数学家, 1912 − 1954 1912-1954 1912−1954
CPU(中央处理器)的主要指标为主频和字长。
CPU是微机的核心部件,是决定微机性能的关键部件。 20 20 20 世纪 70 70 70 年代微型机的CPU问世,微型计算机的核心部件微处理器从Intel 4004
,80286
,80386
,80486
发展到 Pentium II/III
和 Pentium 4
,数位从 4 4 4 位、 8 8 8 位、 16 16 16 位、 32 32 32 位发展到 64 64 64 位,主频从几 M H Z MHZ MHZ 到今天的数 G H Z GHZ GHZ 以上( 1 G H Z = 1000 M H Z 1GHZ=1000MHZ 1GHZ=1000MHZ),CPU芯片里集成的晶体管数由 2 2 2 万个跃升到 1000 1000 1000 万个以上。
世界上第一个CPU:Inter 4004
。
进制转换: 1 T B = 1024 G B = 102 4 2 M B = 102 4 3 K B = 102 4 4 B 1TB=1024GB=1024^2MB=1024^3KB=1024^4B 1TB=1024GB=10242MB=10243KB=10244B
各种存储器读取速度比较:Cache
> > > RAM
> > > ROM
> > > 外存 离CPU越近,速度越快
总线结构可分为:数据,地址,控制总线。
B I O S BIOS BIOS 是存放在 R O M ROM ROM 芯片上的一个程序。
计算机的软件:
C/C++
、Pascal/Object Pascal(Delphi)
等;解释性语言有 ASP
、PHP
、Java
、JavaScript
、VBScript
、Perl
、Python
、Ruby
等。16 16 16 位地址总线的寻址空间: 64 K B 64 KB 64KB , 32 32 32 位地址总线的寻址空间: 4 G B 4GB 4GB 。
I P IP IP 地址的分类
A类 I P IP IP 地址:
0.0.0.0 - 127.255.255.255
B类 I P IP IP 地址:
128.0.0.0 - 191.255.255.255
C类 I P IP IP 地址:
192.0.0.0 - 223.255.255.255
D类 I P IP IP 地址:
224.0.0.0 - 239.255.255.255
E类 I P IP IP 地址:
240.0.0.0 - 247.255.255.255
T C P TCP TCP 协议属于传输层。
字节是存储器系统的最小存取单位。
英文编码: A S C I I ASCII ASCII 码。 A S C I I ASCII ASCII 编码是由美国国家标准委员会制定的一种包括数字、字母、通用符号和控制符号在内的字符编码集,全称叫美国国家信息交换标准代码(American Standard Code for Information Interchange)。
原码:原码就是符号位加上真值的绝对值,即用第一位( + = 0 , − = 1 + = 0,-=1 +=0,−=1)表示符号,其余位表示值。
+ 1 = 00000001 , − 1 = 10000001 +1 = 0000 0001, -1=1000 0001 +1=00000001,−1=10000001
反码:正数的反码是其本身,负数的反码是在其原码的基础上,符号位不变,其余各个位取反。
+ 1 = [ 00000001 ] 原 = [ 00000001 ] 反 +1 = [0000 0001]_原 = [0000 0001]_反 +1=[00000001]原=[00000001]反
− 1 = [ 10000001 ] 原 = [ 11111110 ] 反 -1 = [1000 0001]_原 = [1111 1110]_反 −1=[10000001]原=[11111110]反
正数的补码就是其本身,负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后 + 1 +1 +1。(即在反码的基础上 + 1 +1 +1)
+ 1 = [ 00000001 ] 原 = [ 00000001 ] 反 = [ 00000001 ] 补 +1 = [0000 0001]_原 = [0000 0001]_反 = [0000 0001]_补 +1=[00000001]原=[00000001]反=[00000001]补
− 1 = [ 10000001 ] 原 = [ 11111110 ] 反 = [ 11111111 ] 补 -1 = [1000 0001]_原 = [1111 1110]_反 = [1111 1111]_补 −1=[10000001]原=[11111110]反=[11111111]补
传值只是把其值传给副本,副本改变(比如交换)但原值不改变。传址是是把变量的地址传给地址变量,如果修改其变量所指的内容,原值就会改变。
加了 &
是传址调用。
约瑟夫环、幻方、求逆序对、归并排序相关操作、求逆序对、快速幂、组合数学、杨辉三角、二进制、搜索(遍历)、 gcd \gcd gcd 、 e x gcd ex\gcd exgcd、最长上升子序列、最长公共子序列、最长公共上升子序列、康拓展开……
其实主要还是以做题为主(模板题)。
推荐书籍:《算法竞赛进阶指南》
推荐网站:牛客网
地址总线的位数决定了CPU可直接寻址的内存空间大小,例如地址总线为 16 16 16 位,其最大的可寻址空间为 64 K B 64KB 64KB 。如果地址总线是 32 32 32 位,则理论上最大可寻址的内存空间为( )。
A. 128 K B 128KB 128KB B. 1 M B 1MB 1MB C. 1 G B 1GB 1GB D. 4 G B 4GB 4GB
正解: D \color{white}{D} D
在计算机显示器所使用的 R G B RGB RGB 颜色模型中,()属于三原色之一。
A. 黄色 B. 蓝色 D. 绿色 C. 紫色
正解: B D \color{white}{BD} BD
R ⇒ R e d , G ⇒ G r e e n , B ⇒ B l u e R \Rightarrow Red , \ G \Rightarrow Green, \ B \Rightarrow Blue R⇒Red, G⇒Green, B⇒Blue
以下( )属于互联网上的 E-mail
服务协议。
A. HTTP
B. FTP
C. POP3
D. SMTP
正解: C D \color{white}{CD} CD
常识,记牢!!!
以下关于计算复杂度的说法中,正确的有( )。
A. 如果一个问题不存在多项式时间的算法,那它一定是 N P NP NP 类问题
B. 如果一个问题不存在多项式时间的算法,那它一定不是 P P P 类问题
C. 如果一个问题不存在多项式空间的算法,那它一定是 N P NP NP 类问题
D. 如果一个问题不存在多项式空间的算法,那它一定不是 P P P 类问题
正解: B D \color{white}{BD} BD
对于一棵二叉树,独立集是指两两互不相邻的节点构成的集合。例如,图 1 1 1 有 5 5 5 个不同的独立集( 1 1 1 个双点集合、 3 3 3 个单点集合、 1 1 1 个空集),图 2 2 2 有 14 14 14 个不同的独立集。那么,图 3 3 3 有_________个不同的独立集。
正解: 5536 \color{white}{5536} 5536
阅读程序:
#include
#include
using namespace std;
int lefts[20], rights[20], father[20];
string s1, s2, s3;
int n, ans;
void calc(int x, int dep)
{
ans = ans + dep*(s1[x] - 'A' + 1);
if (lefts[x] >= 0) calc(lefts[x], dep+1);
if (rights[x] >= 0) calc(rights[x], dep+1);
}
void check(int x)
{
if (lefts[x] >= 0) check(lefts[x]);
s3 = s3 + s1[x];
if (rights[x] >= 0) check(rights[x]);
}
void dfs(int x, int th)
{
if (th == n)
{
s3 = "";
check(0);
if (s3 == s2)
{
ans = 0;
calc(0, 1);
cout<<ans<<endl;
}
return;
}
if (lefts[x] == -1 && rights[x] == -1)
{
lefts[x] = th;
father[th] = x;
dfs(th, th+1);
father[th] = -1;
lefts[x] = -1;
}
if (rights[x] == -1)
{
rights[x] = th;
father[th] = x;
dfs(th, th+1);
father[th] = -1;
rights[x] = -1;
}
if (father[x] >= 0) dfs(father[x], th);
}
int main()
{
cin>>s1;
cin>>s2;
n = s1.size();
memset(lefts, -1, sizeof(lefts));
memset(rights, -1, sizeof(rights));
memset(father, -1, sizeof(father));
dfs(0, 1);
}
输入:
ABCDEF
BCAEDF
正确输出: 55 \color{white}{55} 55
如果互连的局域网高层分别采用 T C P / I P TCP/IP TCP/IP 协议与 S P X / I P X SPX/IPX SPX/IPX 协议,那么我们可以选择的互连设备应该是()。
A. 中继器 B. 网桥 C. 网卡 D. 路由器
正解: D \color{white}{D} D
在待排序的数据表已经为有序时,下列排序算法中时间复杂度会减少的是()。
A. 堆排序 B. 希尔排序 C. 冒泡排序 D. 插入排序
正解: B D \color{white}{BD} BD
见上文各种排序算法详解
下列关于排序说法正确的是()。
A、 插入排序、冒泡排序是稳定的
B、 选择排序的时间复杂度为 O ( n 2 ) O(n^2) O(n2)
C、 选择排序、希尔排序、快速排序、堆排序是不稳定的
D、 希尔排序、快速排序、堆排序的时间复杂度为 O ( n log n ) O(n \log n) O(nlogn)
正解: A B C \color{white}{ABC} ABC
见上文各种排序算法详解
阅读程序:
#include
#include
using namespace std;
int a[33],b[33];
void ssort(int x,int y){
if(y-x>1){
int m=(x+y)/2;
ssort(x,m);
ssort(m+1,y);
int k=x;
for(int i=x;i<=m;i++){
b[k]=a[i];b[k+1]=a[m+i-x+1];
k+=2;
}
for(int i=x;i<=y;i++) a[i]=b[i];
}
}
int main() {
for(int i=1;i<=16;i++) a[i]=i;
ssort(1,16);
for(int i=1;i<=16;i++) cout<<setw(3)<<a[i];
cout<<endl;
return 0;
}
//这道题请严格按照输出格式来,注意行首和行间空格,行末空格忽略
答案:
1 9 5 13 3 11 7 15 2 10 6 14 4 12 8 16
下列属于冯诺依曼计算机模型的核心思想有()。
A. 采用二进制表示数据和指令
B. 采用“存储程序”工作方式
C. 计算机硬件有五大部件(运算器、控制器、存储器、输入和输出设备)
D. 结构化程序设计方法
正解: A B C \color{white}{ABC} ABC
计算机基础知识:冯·诺依曼思想
就地(原地)排序是指:基本上不需要额外辅助的的空间,允许少量额外的辅助变量进行的排序。以下排序中属于就地排序的是()
A. 基数排序 B. 希尔排序 C. 归并排序 D.快速排序
正解: B D \color{white}{BD} BD
排序算法 辅助空间代价 直接插入排序 O ( 1 ) O(1) O(1) 希尔排序 O ( 1 ) O(1) O(1) 冒泡排序 O ( 1 ) O(1) O(1) 快速排序 O ( log n ) O(\log n) O(logn) 属于就地排序 选择排序 O ( 1 ) O(1) O(1) 堆排序 O ( 1 ) O(1) O(1) 归并排序 O ( n ) O(n) O(n) 基数排序 O ( n + r ) O(n+r) O(n+r)
下列关于图的说法正确的是()
A. 欧拉图的每一个顶点都能作为某条欧拉闭迹的起点
B. 一个图有欧拉闭迹当且仅当该图有零个奇点
C. 若一个无向图有奇数条边,则它必然不是二分图
D、若 G G G 是汉密尔顿图,则对 G G G 上的汉密尔顿圈 C C C,任意删去 n n n 个点,最多可将 C C C 划分为 n n n 段,反之亦然
正解: A \color{white}{A} A
T C P TCP TCP 协议属于哪一层协议( )。
A. 应用层 B. 传输层 C. 网络层 D. 数据链路层
正解: B \color{white}{B} B
对长度位 n n n 的有序单链表,若检索每个元素概率相等,则顺序检索到表中任一元素的平均检索长度为()。
A. n 2 \dfrac{n}{2} 2n B. n + 1 2 \dfrac{n+1}{2} 2n+1 C. n − 1 2 \dfrac{n-1}{2} 2n−1 D. n 4 \dfrac{n}{4} 4n
正解: B \color{white}{B} B
如图所示,图中每条边上的数字表示该边的长度,则从A到E的最短距离是()。
正解: 15 \color{white}{15} 15
路径为: A − B − C − F − H − I − E \color{white}{A-B-C-F-H-I-E} A−B−C−F−H−I−E
程序填空
#include
const int SIZE = 100;
int stack1[SIZE], stack2[SIZE];
int top1, top2;
int n, m, i, j;
void clearStack()
{
int i;
for ( i = top1; i < SIZE; i++ )
stack[i] = 0;
for ( i = top2; i < SIZE; i++ )
stack[i] = 0;
}
int main()
{
scanf( "%d,%d", &n, &m );
for ( i = 0; i < n; i++ )
scanf( "%d", &stack1[i] );
top1 = ______(1)______;
top2 = ______(2)______;
for ( j = 0; j < m; j++ )
{
scanf( "%d", &i );
while ( i < top1 - 1 )
{
top1--;
______(3)______;
top2++;
}
while ( i > top1 - 1 )
{
top2--;
______(4)______;
top1++;
}
clearstack();
printf( "%d\n", stack1[______(5)______] );
}
return(0);
}
(2):________________
正解: 1 \color{white}{\texttt{1}} 1
因为
top
都是指向栈顶元素的下一个元素下标。所以当栈为空时,top
指向的下标为 1 \color{white}{1} 1
程序填空
#include
const int SIZE=100;
int matrix[SIZE+1][SIZE+1];
int rowsum[SIZE+1][SIZE+1]; //rowsum[i][j]记录第i行前j个数的和
int m,n,i,j,first,last,area,ans;
int main()
{
scanf(“%d %d”,&m,&n);
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
scanf(“%d”,&matrix[i][j]);
ans=matrix_____(1)_____;
for(i=1;i<=m;i++) _____(2)_____;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
rowsum[i][j]=_____(3)_____;
for(first=1;first<=n;first++)
for(last=first;last<=n;last++)
{
_____(4)_____;
for(i=1;i<=m;i++)
{
area+=_____(5) ;
if(area>ans) ans=area;
if(area<0)area=0;
}
}
printf(“%d\n”,ans);
return 0;
}
(3):__________
(5):__________
正解: rowsum[i][j-1] + matrix[i][j] \color{white}{\texttt{rowsum[i][j-1] + matrix[i][j]}} rowsum[i][j-1] + matrix[i][j]
rowsum[i][last]-rowsum[i][first-1] \color{white}{\texttt{rowsum[i][last]-rowsum[i][first-1]}} rowsum[i][last]-rowsum[i][first-1]
若 f [ 1 ] = 1 , f [ 2 ] = 5 6 , 3 × f [ n + 1 ] = 5 × f [ n ] − 2 × f [ n − 1 ] f[1]=1,f[2]= \dfrac{5}{6} ,3 \times f[n+1]=5 \times f[n]-2 \times f[n-1] f[1]=1,f[2]=65,3×f[n+1]=5×f[n]−2×f[n−1],则随着 i i i 的增大, f [ i ] f[i] f[i] 将接近()。
A. 1 3 \dfrac{1}{3} 31 B. 2 − 1 \sqrt{2}-1 2−1 C. 1 2 \dfrac{1}{2} 21 D. 1 1 1
正解: C \color{white} {C} C
最大容量为 n n n 的循环队列,队尾指针是 rear
,队头是 front
,则队空的条件是()。
A. (rear+1)%n==front
B. rear==front
C. rear+1==front
D. (rear-1)%n==front
正解: B \color{white}{B} B
循环队列的基础知识。
二维数组 A A A 的每个元素是由 10 10 10 个字符组成的串,其行下标 i = 0 , 1 , … , 8 i=0,1,…,8 i=0,1,…,8,列下标 j = 1 , 2 , … , 10 j=1,2,…,10 j=1,2,…,10。若 A A A 按行先存储,设每个字符占一个字节,元素 A [ 8 ] [ 5 ] A[8][5] A[8][5] 的起始地址与当 A A A 按列先存储时的元素()的起始地址相同。
A. A [ 8 ] [ 5 ] A[8][5] A[8][5] B. A [ 3 ] [ 10 ] A[3][10] A[3][10] C. A [ 5 ] [ 8 ] A[5][8] A[5][8] D. A [ 0 ] [ 9 ] A[0][9] A[0][9]
正解: B \color{white}{B} B
你一定玩过汉诺塔游戏:有三根柱子,在一根柱子上有若干盘子,保证自上而下从小到大堆放,现要将所有盘子移动到最后一根柱子上,保证:1、移动过程中,始终保证小盘子在大盘子上;2、在三根柱子间一次只能移动一个盘子。现在规则稍有一些变化(相信难不倒聪明的你)——四根柱子,其他规则不变,问把 A A A 柱子上 20 20 20 个盘子移动到 D D D 上的最小步数为()。
A. 289 289 289 B. 2023 2023 2023 C. 524287 524287 524287 D. 1048575 1048575 1048575
正解: A \color{white}{A} A
在等腰直角三角形 A B C ABC ABC 中,过直角顶点 C C C 在 ∠ A C B ∠ACB ∠ACB 内部任作一射线 C M CM CM,与线段 A B AB AB 交于点 M M M,求 A M < A C AM
A. 1 3 \dfrac{1}{\sqrt{3}} 31 B. 1 2 \dfrac{1}{2} 21 C. 2 2 \dfrac{2}{\sqrt{2}} 22 D. 3 4 \dfrac{3}{4} 43
正解: D \color{white}{D} D
按角度来计算,不是按线段长度来计算
若A=False,B=True,C=True,D=False,则下列逻辑运算真的有()
A. (A∧B)V(C∧D) B. ((A∧¬B)VD)∧B C. ((¬A→¬B)∧C)VD D. ¬A∧(¬D→¬C)→¬B
正解: D \color{white}{D} D
→ 是蕴含的意思。
在整数的补码表示法中,以下说法正确的是( )。
A.只有负整数的编码最高位为1
B.在编码的位数确定后,所能表示的最小整数和最大整数的绝对值相同
C.整数0有正零和负零两个编码
D.两个用补码表示的数相加时,如果在最高位产生进位,则表示运算溢出
正解: A \color{white}{A} A
下列不是Internet提供的服务有( )
A. 信息检索工具 B. 电子邮件 C. 文件传输协议FTP D. 数字视频影像服务
正解: D \color{white}{D} D