NOIP2015普及组初赛难点整理

选择题

  1. 前序遍历序列与中序遍历序列相同的二叉树为( )。
    A. 根结点无左子树的二叉树
    B. 根结点无右子树的二叉树
    C. 只有根结点的二叉树或非叶子结点只有左子树的二叉树
    D. 只有根结点的二叉树或非叶子结点只有右子树的二叉树

【解析】要使前序遍历序列与中序遍历序列相同,对于任意非叶子结点,不能存在左子树,否则前序遍历序列与中序遍历序列不可能相同。除此之外,只有根结点的二叉树,前序、中序、后序遍历都相同。

  1. 如果根的高度为 1 1 1,具有 61 61 61 个结点的完全二叉树的高度为( 6)。

【解析】有 n n n个结点完的全二叉树高度 h = ⌊ l o g 2 n ⌋ + 1 h=\lfloor log_2^n \rfloor+1 h=log2n+1,所以答案为 ⌊ l o g 2 61 ⌋ + 1 = 6 \lfloor log_2^{61} \rfloor+1=6 log261+1=6

  1. 设某算法的计算时间表示为递推关系式 T ( n ) = T ( n − 1 ) + n T(n)= T(n-1)+ n T(n)=T(n1)+n n n n 为正整数)及 T ( 0 ) = 1 T(0)= 1 T(0)=1,则该算法的时间复杂度为( O ( n 2 ) O(n^2) O(n2) )。

【解析】通过递推式,可以得到: T ( n ) = T ( n − 1 ) + n = T ( n − 2 ) + n − 1 + n = T ( n − 3 ) + n − 2 + n − 1 + n = T ( 0 ) + 1 + 2 + . . . + n T(n)= T(n-1)+ n=T(n-2)+n-1+n=T(n-3)+n-2+n-1+n=T(0) +1+2+...+n T(n)=T(n1)+n=T(n2)+n1+n=T(n3)+n2+n1+n=T(0)+1+2+...+n

整理后: T ( n ) = 1 + 2 + . . . + n = ( 1 + n ) × n / 2 T(n)=1+2+...+n=(1+n)\times n/2 T(n)=1+2+...+n=(1+n)×n/2,所以该算法的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

问题求解

  1. 重新排列 1234 1234 1234 使得每一个数字都不在原来的位置上,一共有(9 )种排法。

【解析】错排问题。 问题规模较小,也可以手动枚举。错排的方案有:
214323412413314234123421412343124321,一共9种。
解决错排问题的算法思想是将排列第n个数的情况 f ( n ) f(n) f(n)分为两类:

  • 前面 n − 1 n-1 n1个数已经完成错排,那么从前面 n − 1 n-1 n1个数中任意挑出一个数与第 n n n个数进行交换,此时构成 n n n个数的错排,方案总数为 ( n − 1 ) × f ( n − 1 ) (n-1)\times f(n-1) (n1)×f(n1)
  • 前面 n − 1 n-1 n1个数只有一个数在自己原来位置,即已经构成 n − 2 n-2 n2个数的错排,此时将该数与第 n n n个数进行交换,则也能构成 n n n个数的错排,方案总数为 ( n − 1 ) × f ( n − 2 ) (n-1)\times f(n-2) (n1)×f(n2)

所以, n n n个数的错排方案总数为: f ( n ) = ( n − 1 ) × ( f ( n − 1 ) + f ( n − 2 ) ) f(n)=(n-1)\times(f(n-1)+f(n-2)) f(n)=(n1)×(f(n1)+f(n2))
初始状态: f ( 1 ) = 0 , f ( 2 ) = 1 , f ( 3 ) = 2 , f ( 4 ) = 9 f(1)=0, f(2)=1,f(3)=2,f(4)=9 f(1)=0,f(2)=1,f(3)=2,f(4)=9

答案:9

  1. 一棵结点数为 2015 2015 2015 的二叉树最多有( 1008)个叶子结点。

【解析】二叉树中结点总数 n = n 0 + n 1 + n 2 n=n_0+n_1+n_2 n=n0+n1+n2。根据二叉树的性质: n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1,要保证二叉树中叶子结点最多,那么 n 1 n_1 n1要尽可能的少,此时的二叉树一定是一棵完全二叉树。根据完全二叉树的性质,最后一个拥有孩子的结点的父结点的编号 = n / 2 =n/2 =n/2,那么一棵结点数为:
2015 2015 2015 的二叉树最多有 2015 − 2015 / 2 = 1008 2015-2015/2=1008 20152015/2=1008个叶子结点。

完善程序

  1. (打印月历)输入月份 m ( 1 ≤ m ≤ 12 ) m(1 \le m \le 12) m(1m12),按一定格式打印 2015 2015 2015 m m m 月的月历。例如,2015 年一月的月历打印效果如下(第一列为周日):在这里插入图片描述
#include<iostream>
using namespace std;
const int dayNum[]={-1,31,28,31,30,31,30,31,31,30,31,30,31};
int m, offset, i;
int main()
{
    cin >> m;
    cout <<"S	M	T	W	T	F	S"<<endl;//'	'为tab制表符
    ①;
    for (i = 1; i < m; i++)
        offset = ②;
    for (i = 0; i < offset; i++)
        cout <<'	';
    for (i = 1; i <= ③;i++)
    {
        cout << ④;
        if(i==dayNum[m]||⑤==0)
            cout << endl;
        else
            cout << '	';
    }
    return 0;
}

【解析】通过偏移数offset将每个月的日期输出到对应的星期上。
空①,offset记录上个月的偏移数,1月份的偏移数为4,所以此空应填:offset=4
空②,计算第m个月的偏移数,所以应加上前一个月的天数并对7取余数,(offset+dayNum[i])%7
空③,输出第m个月的日期,dayNum[m] 空④,输出循环变量i表示的日期
空⑤,换行条件,当前日期加上偏移数如果是7的倍数时换行,所以应填入:(offset+i)%7

  1. (中位数)给定 n n n n n n 为奇数且小于 1000 1000 1000)个整数,整数的范围在 0   m 0~m 0 m 0 < m < 2 31 0 \lt m \lt 2^{31} 0<m<231)之间,请使用二分法求这 nn 个整数的中位数。所谓中位数,是指将这 n n n 个数排序之后,排在正中间的数。
#include <iostream>
using namespace std;
const int MAXN = 1000;
int n,i,lbound,rbound,mid,m,count;
int x[MAXN];
int main()
{
    cin >> n >> m;
    for(i = 0; i < n; i++)
        cin >> x[i];
    lbound = 0;rbound = m;
    while(①) {
        mid=(lbound+rbound)/2;
        ②;
        for(i = 0; i < n; i++)
        {
            if(③)
                ④;
        }
        if(count > n/2)
            lbound = mid + 1;
        else
            ⑤;
    }
    cout << rbound << endl;
    return 0;
}

【解析】二分搜索求中位数。lboundrbound即中位数的左右边界。

  • 空①,二分搜索的循环条件,即lbound<rbound
  • 空②,count记录x[]中比中位数mid大的数的个数,此时应该初始化为0,所以此空应填入count=0
  • 空③,if(count > n/2) lbound = mid + 1;表示:如果count的个数超过了一半,再到更大的值区间中搜索中位数,即mid不够大。所以此空应填入x[i]>mid
  • 空④,count++
  • 空⑤,count <= n/2,到更小的值空间搜索,此时rbound=mid

猜你喜欢

转载自blog.csdn.net/qiaoxinwei/article/details/107890104