剪枝相关
比赛时遇到了挺多剪枝相关的题,但是只会套板子,趁着有时间学习总结一下
定义
DFS之剪枝与优化指的是在执行深度优先搜索(DFS, Depth-First Search)时,采取的一系列策略来减少搜索空间,避免无效计算,从而加速找到问题的解。剪枝是指在搜索过程中,当遇到某些条件不符合解的要求或者可以预判后续搜索不会产生有效解时,直接放弃这条搜索路径,这一过程称为剪枝。优化则是指通过调整搜索策略、顺序等,提高搜索效率。
题目(收集ing……)
首尾剪枝
1 | from Crypto.Util.number import * |
题目给出p 与 q 的反方向二进制的异或值,根据异或操作的特性,可知如果当前需搜索的最高位为”1”,则对应两种可能:p该位为1,q对应低位为0;p该位为0,q对应低位为1。对应的剪枝条件为
1.将p、q未搜索到的位全填0,乘积应小于n
2.将p、q未搜索到的位全填1,乘积应大于n
3.p、q 低 k 位乘积再取低 k 位,应与 n 的低 k 位相同
首先定义搜索函数
1 | def find(ph,qh,pl,ql): |
根据条件进行剪枝操作
1 | if(l == 128): |
2(名称待定)
1 | from Crypto.Util.number import * |
首先关注一下((1 << 1024) - 1)//3这个数,发现是10101010……01,适合剪枝,根据逻辑与操作的特点:全一为一,有零为零。且p*q的低位等于n的低位.
首先知道p和q末尾必是01,再逐步从后向前进行剪枝,又因为只有奇数位有1,每次可以操作两位,用01和00搭配可能性即可
1 | from Cryptodome.Util.number import inverse, long_to_bytes |
3,已知p^q
1 | from Crypto.Util.number import * |
搜索条件:
从低位向高位搜索
若xor当前位为1,则可能为两种情况:p为1,q为0 或者 p为0,q为1;反之xor当前位为0,则p为1,q为1 或者 p为0,q为0.
剪枝条件:
- 将p和q剩下位全部填充为1,需要满足 p*q > n
- 将p和q剩下位全部填充为0,需要满足 p*q < n
其实算是第一道题的简化版,当p*q=n或者n mod p=0时结束
1 | n = 81273634095521392491945168120330007101677085824054016784875224305683560308213 |
4,p ^(q >> 16)
1 | from Crypto.Util.number import * |
这里只看一下通过剪枝分解n的操作,其实与上一道题差别不大,但是剪枝条件有所变化。
1,(pp ^ (qq >> 16)) % (2 ** l) == gift % (2 ** l)
2,pp * qq % (2 ** l) == N % (2 ** l)
第二点感觉是都有的,第一点根据题目信息改动即可
tips:因为gift是p异或q右移16位的结果,所以p的最后一位1相当于异或了q的第十七位。这也就是为什么只搜p而不是同时搜p,q,传入的也不是q的末位1而是q的末17位,在调用函数的时候才会有爆破了q后17位的操作。
1 | N=75000029602085996700582008490482326525611947919932949726582734167668021800854674616074297109962078048435714672088452939300776268788888016125632084529419230038436738761550906906671010312930801751000022200360857089338231002088730471277277319253053479367509575754258003761447489654232217266317081318035524086377 |
小结
时间关系先暂时收录这四种题型,其实归根结底都是一种问题,即通过p*q=n和题目给出的条件进行剪枝分解n,
关于剪枝,其实感觉没有特定的做法,而是一种思想,就是通过各种方法减少搜索规模,从而提高效率。目前遇到的剪枝都是在RSA中,或许其他的密码体系也会有着这种思想存在?
还感觉比较重要的一点是搜索的顺序,剪枝是一种方法,但是有些时候我们可以通过该变搜索的顺序来进一步提高效率,包括上述提到的首尾剪枝,低位向高位剪枝……继续深挖下去发现涉及到更深一步的算法待后续研究。任重而道远捏{}