武科带算法复习

第三章

5. 汉诺塔问题

// 从a经过b移动n个盘子到c
void hanoi(int n, int a, int b, int c) {
    hanoi(n-1, a, c, b);
    print(f"从{a}移1个到{c}");
    hanoi(n-1, b, a, c);
}

6. 整数分划问题

求一个函数P(n),返回n的不同分划数。
例子:P(6)=6,因为有如下分划:
6
5+1
4+2
3+3
2+2+2
1+1+1+1+1+1

设函数Q(a,b),表示a的所有加数不大于b的分划数。P(n)=Q(n,n)。
则:
(1) Q(a,a)=Q(a,a-1)+1
如,6的分划有6=6和其他不含6的分划。
(2) Q(a,b)=Q(a,b-1)+Q(a-b,b)
a的不大于b分划包括含b的和不含b的,第一项表示不含b的,第二项表示含b的。

7. 输出每一位(低到高)

void print_digits(int n){
    if(n<10) print(n);
    else
    {
        print(n % 10);
        print_digits(n / 10);
    }
}

8. 输出每一位(高到低)

void print_digits(int n){
    if(n<10) print(n);
    else
    {
        print_digits(n / 10);
        print(n % 10);
    }
}

10. 输出组合(m选k)

例如,m=5, k=3,输出结果为
5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1

int K = 0;
int a[100];

// comb(m,k)负责固定a[k],递归下一层comb(m-1,k-1)固定a[k-1],
// 回来后a[k]取下一个值。
// 如果k等于1,就不需要递归,直接输出每个值即可。
void comb(int m, int k) {
    // mm 是下一层递归的m 
    for(int i = m; i >=k ; i--) {
        a[k] = i;
        if(k > 1)
            comb(i-1,k-1);
        else {
            for(int j = K; j > 0; j--)
                std::cout << a[j] << " ";
            std::cout << "\n";
        }
    } 
}

void C(int m, int k)
{
    K = k;
    memset(a, 0, sizeof(a));
    comb(m,k);
}

20. 趣味矩阵

a[i][j]表示第i行第j列。

35. 称重问题

有10箱子产品,每箱1000件,正品每件100克,其中有几箱为次品,每件次品比正品轻10克,问是否能只称1次,就找出哪些是次品。

第一箱取1个,第二箱取2个,第三箱取4个,第四箱取8个…

比如轻了70g,就是第1、2、3箱是次品。

36. 狼找兔子问题/循环移数问题

循环移数的问题:有n个数,循环后移k个位置。只有1个辅助空间。如何移动?


可以分成gcd(n,k)组,每组内的数进行循环移动。如n=12,k=8时,分组如下:

1 2 3 4 1 2 3 4 1 2 3 4

据此编码即可。

狼找兔子问题:有一个狼要找兔子吃,狼每隔k个洞找一下,有n个洞,找到头就返回去,请问兔子躲哪里永远不会被找到?

同理,还是分组,只要兔子不在狼那一组就没事。如果gcd(n,k)=1即n,k互质,则兔子必死。

39. 中国余数问题

x ≡ r 1 ( m o d    t 1 ) x \equiv r_1(\mod t_1) xr1(modt1)
x ≡ r 2 ( m o d    t 2 ) x \equiv r_2(\mod t_2) xr2(modt2)
x ≡ r 3 ( m o d    t 3 ) x \equiv r_3(\mod t_3) xr3(modt3)
n n n

n = t 2 t 3 k 1 r 1 + t 1 t 2 k 2 r 2 + t 1 t 2 k 3 r 3 n=t_2t_3k_1r_1+ t_1t_2k_2r_2+ t_1t_2k_3r_3 n=t2t3k1r1+t1t2k2r2+t1t2k3r3
其中: k i , i = 1 , 2 , 3 k_i, i=1,2,3 ki,i=1,2,3应该满足以下条件
t 2 t 3 k 1 ≡ 1 ( m o d    t 1 ) t_2t_3k_1 \equiv 1(\mod t_1) t2t3k11(modt1)
t 1 t 2 k 2 ≡ 1 ( m o d    t 2 ) t_1t_2k_2 \equiv 1(\mod t_2) t1t2k21(modt2)
t 1 t 2 k 3 ≡ 1 ( m o d    t 3 ) t_1t_2k_3 \equiv 1(\mod t_3) t1t2k31(modt3)

找到这三个系数带入即可得 n n n。最后结果模一个 t 1 t 2 t 3 t_1t_2t_3 t1t2t3

40. 上台阶问题

有n阶台阶,一次能上1级或2级,求有几种上法。

倒过来想:
f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n-1) + f(n-2) f(n)=f(n1)+f(n2)

第四章

倒推法

5. 穿越沙漠问题

车子穿越1000m的沙漠,总装油量500升,耗油量1L/km,请问如何建立油站最省油(求油站的位置和油量)?

  • 汽车是一点一点“挪”过去的,即在起点和第一站之间往返建立好第一站后,就只用第一站的油在第一站和第二站之间往返(再也不回起点了),建立好第二站后,就只用第二站的油在第二站和第三站之间往返(再也不回第一站了)…

  • 建立好下一站后,上一站的油刚好用完,车内恰好没油,一切从0开始。

  • 每次向终点出发时汽车应该满载,没有为什么,贪婪的思想。

  • 倒着推,从终点到倒数第一站,一定是500m才能让第一站的油刚好用完。倒数第一站到倒数第二站之间的路程要走三次,其中两次是向终点出发,应该满载,所以倒数第二站存1000L

  • 接下来看距离,因为倒数第一站的油(500L)全部来自倒数第二站,所以倒数第二站还剩下1000-500=500L,这500L全部用于往返倒数一二站,这段路走了3次,所以距离为500/3km。

蛮力法vs聪明法

12. 狱吏问题

让狱吏n次通过一排锁着的n间牢房,第k次通过,转动第k,2k,3k,…间牢房的钥匙(切换开/关状态,即开变关、关变开)。问经过n次后,哪些牢房的锁是开的?

:(不用蛮力的方法)
利用因子个数,比如4号门,它的因子有1、2、4,说明它在第1、2、4轮会切换状态。切换了3次,最终应该是开的(假设n>=4)。

那么求一个门最终开不开,就是求它的不同因子的个数,奇数就开,偶数就不开。

然后我们发现,只有完全平方数拥有奇数个不同因子,因为因子都是成对出现的,“不同因子的个数”为奇数,说明有一对因子是一样的。

最后发现,解决这个问题,只需找到不大于n的完全平方数即可

分治法

14. 残缺棋盘


分治算法,简单说就是三个小块把空当凑到中间,正好再填一个。

15. 求数列的最大子列和


分治算法,将数列等分成2段,则最大子列的位置分为3中情况。

  • 全部在左段
  • 全部在右段
  • 跨左右段

前两种情况递归解决,第三种情况从中间向两侧各找最大子列,然后合并即是整体的最大子列。

17. 找数组中第二小的数


分治算法,分成两段,各求最小2个数。然后再4个数中选出最小的2个。

18. 找数组中第k小的数


用快速排序的第一步“切分“。先得到一个锚点p,p左边的数都比p小,右边的都比p大。
然后数p左边有几个,记作l。

如果l=k-1那么p就是答案
如果l>k-1,那么就递归在左半边找第k个数
如果l<k-1,那么就递归在右半边找第k-p个数

贪心法

通过取局部最优达到全局最优的策略。

19. 删数字


若各位数字递增,则删除最后一个数字,否则删除第一个递减区间的首字符。然后回到串首,按上述规则再删除下一个数字。重复以上过程s次即可。

23. 取数游戏

2个人轮流取2n个数中的n个数(全程明牌),取数之和大者为胜。请问先手如何永远胜利?

先手先看奇位置上的数的和大还是偶位置上的数的和大,哪个大就确保自己只取这些数,对面取不到这些数即可。换言之,不让对手取两个连续的数就行。

动态规划

递归+保存结果 的

25. 投资问题

将n元分配给m个项目, g i ( x ) g_i(x) gi(x)为第i个项目分配得x元所得到的利润。求最大利润的分配方案。

f i ( x ) f_i(x) fi(x)为将资源 x x x分配给前 i i i个项目所得到的最大利润,则:

f 1 ( x ) = g 1 ( x ) f_1(x)=g_1(x) f1(x)=g1(x)

f i ( x ) = m a x { g i ( k ) + f i − 1 ( x − k ) } k = 0 x f_i(x)=max\{g_i(k)+f_{i-1}(x-k)\}_{k=0}^{x} fi(x)=max{gi(k)+fi1(xk)}k=0x

26. 矩阵连乘问题

构造数组 r i r_i ri。表示第 i + 1 i+1 i+1个矩阵的行数和第 i i i个矩阵的列数。

矩阵 M i . . . M j Mi...Mj Mi...Mj的最小乘法次数
f ( i , j ) = 0 ( i = j ) f ( i , j ) = r i r i + 1 r i + 2 ( i = j − 1 ) f ( i , j ) = m i n ( f ( i , k ) + f ( k + 1 , j ) + r i r k + 1 r j + 1 ) ( i ≤ k < j ) f(i,j)= 0 (i=j) \\ f(i,j)=r_ir_{i+1}r_{i+2} (i=j-1) \\ f(i,j)=min(f(i,k)+f(k+1,j)+r_ir_{k+1}r_{j+1})(i\le k < j) f(i,j)=0(i=j)f(i,j)=riri+1ri+2(i=j1)f(i,j)=min(f(i,k)+f(k+1,j)+rirk+1rj+1)(ik<j)

27. 最长子序列

第五章

子集树:

第1层 1号元素选还是不选
第2层 2号元素选还是不选

2 n 2^n 2n个叶子结点

排列树:

第1层 1号元素放哪(n个选择)
第2层 2号元素放哪(n-1个选择)

n ! n! n!个叶子结点

活结点:还可以展开的结点
E结点:正在展开的结点
死结点:无法再展开的结点

8皇后问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值