北大郭炜算法课笔记整合

一、枚举:

枚举重点关注三个方面:顺序(循环的内外关系、以及枚举时的大小顺序)、范围(循环的范围,往往是作优化用)、变量的变化方式(从大到小&从小到大、※以及一次变化多少)

例1,对于这个题目,我们应该确定的事情,一个是多重循环中谁在内谁在外,再一个是循环的范围,还有就是循环变量是从大到小还是从小到大。

1.循环的内外关系:a、b、c、d依次由外到内--这样可以依次保证a最小、a相等时b最小、ab相等时c最小、abc相等时找到的d最小

2.循环的范围---往往题目中会给出各个变量之间的制约关系,这也是优化枚举策略的重点

※3.循环变量的增减方式--这一条实际上很容易忽略。比如这个题目,给了四种“值小则优先输出”的条件,但是很容易发现,只需要枚举的时候从小到大枚举,并且设计好循环的内外关系(最外层的是最需要“先”保证最小的),就可以求得这样的条件下的结果

                                                                      

例2,一个非常典型的通过“跳着试”来进行优化的题目--如果只是看两个,比如体力和情商,可以一次跳23天(体力的周期),这样就可以首先满足位于体力高峰,然后再看是否同为情商高峰。三个也是同理,可以一次跳过体力和情商(23和28的最小公倍数),来看是否同为智商的高峰。

 例3,也蕴含着枚举题目中的一个很重要的思想----先假设再验证。

 对于不同的假设进行验证即可得出结论

例4,熄灯问题。这种题目,往往会可能具有两种性质中的一种——一种是类似于“最优子结构”的性质--当前行的状态仅由上一行的灯的状态决定。仅由上一行决定也就说明了,后续子问题的状态不会再返回来影响它的状态。当然这个状态,指的是题目需要的状态,比如全灭,而不仅仅指的是特定灯的开或关;另一种就是此题这样的更加简单的子结构,第一行只要决定了,其实所有的都决定了。 

 

①和②的分析非常关键--否则还会引出对于按钮按下的次数&按下的顺序的讨论

解题时往往会需要这种思想--把结论中的一条提出来当作条件,看这个条件成立时另外一个结论是否可以成立,其实有一点点像离散数学里的CP规则(也不怎么符合,因为CP需要的是蕴含或者析取式)。

这个题除了选用位运算外还有一个优化点--一共五行六列,如果枚举第一行的状态,就是2^6=64种,但是同样的,也可以枚举第一列的状态,就变成了2^5=32种

由此题引出的位运算的一些技巧:

1.封装--SetBit,GetBit,FlipBit

①SetBit:把某个数的右数第某位修改成指定的0/1:

void SetBit(int& val,int pos,bool num){
    //参数分别为:要修改的数,右数第几位(注意最右边是第0位!),修改成0/1
    if(num){
    val|=(1<<pos);
    return;
    }
    val&=(~(1<<pos));
}

②GetBit:Getter类函数推荐写作const,让人一看就知道是一个只读的函数

同样的,位置也是从右边开始,下标从0开始

bool GetBit(const int val, int pos)
{
    return val & (1 << pos);
}

③FlipBit:

翻转某一位--当第二个参数(pos)没有传入的时候,把整个数翻转。所以第二个参数的默认值应该是个特殊值,比如-1

????

另外:像这些短小但可能经常使用的函数,为了保证效率,可以均设置为inline函数

其他的一些位运算的典型题,在博客的其他文章里有整理。

二、递归

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值