线性规划最优整数解怎么快速学
分支定届法的基本思路?
分支定届法的基本思路?
分支定界法是两栖学者理查德·卡普(Richard M.Karp)在20世纪60年代发明的,成功解决了涉及65个城市的旅行商问题,创下了当时的纪录。 "分枝定界法 "像树的分支一样展开问题的可行解,然后通过每个分支寻找最优解。
简介
分支定界法也可以用于混合整数规划,这是一种系统化的求解方法。用一般线性规划的单纯形法求得最优解后,将非整数值的决策变量分成两个最接近的整数,在原问题上加上分割条件,形成两个子问题(或分支)分别求解,从而得到目标函数值的上界(上界)或下界(下界),从中找出最优解。
基本思想
1、基本思路
分支定界法是一种应用广泛的算法,技巧性很强,对不同类型的问题有不同的解法。分支定界法的基本思想是搜索约束优化问题的所有可行解(有限个)空间。当算法实现时,所有可行解空间被连续地分成越来越小的子集(称为分支),并为每个子集中的解的值计算一个下界或上界(称为界限)。在每个分支之后,对于那些边界超过已知可行解值的子集,将不再进行分支。这样,可以忽略解决方案的许多子集(即搜索树上的许多节点),从而缩小搜索范围。这个过程一直持续到找到可行解,并且可行解的值不大于任何子集的边界。所以这种算法一般都能找到最优解。
将一个问题分支成子问题并划分这些子问题的步骤称为分支定界法。
2.分支节点的选择
必须对搜索树上的某些点进行分支决策,即边界小于迄今为止所有可行解的最小下界的任何子集(节点)都可能是分支的选择对象(对于求最小值的问题)。如何选择搜索树上的节点作为下一个分支的节点?有两个原则:
1)从最小下界分支(队列FIFO分支定界法):每次计算完界限后,比较搜索树上所有当前叶节点的界限。找到边界最小的节点,就是下一个分支的节点。
?优点:考察的子问题少,能快速得到最优解;
?缺点:需要大量的内存空间来存储很多叶子节点的边界和对应的代价矩阵。
2)从最新的最小下界分支(优先级队列分支定界法):从最新的子集中选择下界最小的节点进行分支。
优点:节省空间;缺点:需要更多的分支操作,需要更多的时间。这两个原则进一步说明了算法设计中时空变换的概念。分支定界法已经成功地应用于解决整数规划问题、生产调度问题、旅行商问题、选址问题、背包问题,并且可行解的数目是有限的。其他问题。对于不同的问题,分支和边界的步骤和内容可能不同,但基本原理是一样的。
步骤
分枝定界法是解决组合优化问题的有效方法,其步骤如下:
第一步:如果问题的目标是最小化,设置当前最优解Z∞的值。
第二步:根据分支规则,从尚未深究的节点(局部解)中选择一个节点,在该节点的下一个层次中将其分成若干个新节点。
步骤3:计算每个新分支节点的下界(LB)。
第四步:测试每个节点的洞察情况。如果该节点满足以下任一条件,则该节点可以是insight,将不再被考虑:
?此节点的下限值大于或等于z值。
?在该节点中找到了具有最小下界的可行解;如果这个条件成立,就需要将可行解与z值进行比较,如果前者较小,就需要将z值更新为可行解的值。
?此节点不能包含可行的解决方案。
第五步:判断是否还有未知数,如果有,进行第二步,如果没有未知数,停止计算,得到最优解。
Kol
整数的计算方法?
首先我们定义一个整数的平方根从非负整数映射到非负整数的函数:我们可以用乘法线性搜索或者二分法搜索得到平方不超过的最大根。通过平方数的数列,我们在线性搜索中只能使用加法,因为两个完全平方数之差是一个奇数列:uint 32 _ t is qrt 0(uint 32 _ t n){ uint 32 _ t delta 3;for(uint 32 _ t square 1;平方n;△2)方三角;返回delta/2-1;}因为问题是关于大整数的,所以我们要把大整数的位数()考虑进去。线性搜索需要多次迭代,每次迭代的加法都需要时间。然而,最坏情况下的二分搜索法需要多次迭代,并且每次乘法都需要时间。但有些数值方法(如牛顿迭代)只适合计算近似,还涉及除法。让 咱们换个思路,参考文章整数平方根。类似长除法的,二进制只需要比较和减法,32位无符号整数的C实现如下:uint 32 _ t is qrt 1(uint 32 _ t n){ uint 32 _ t余数0,根0,除数;for(size _ t I 0;i 16i ) {根1;余数2;余数| n 30N2;//从n除数(根1) 1中提取2 MSBif(除数余数){余数-除数;根;} }返回root这种方法的迭代次数是次(一个整数有多少位),每次迭代的加、减、移位、比较都是一样的。总时间和时间复杂度低于线性和二分搜索法。由于除数和根的关系是固定的,如果空间是一个考虑因素(考虑大整数或硬件实现),可以把这种形式改为节省除数的存储:uint 32 _ t is qrt 2(uint 32 _ t n){ uint 32 _ t remainder 0,root 0;for(size _ t I 0;i 16i ) {根1;根;余数2;余数| n 30N2;//从n if(根余数){余数-根)中提取2 MSB根;} else-root;}返回根1;}接下来我们用C 11泛形式写这个算法,接受任何无符号整数类型:Template TypeName T T I SQRT(Const T N){ T Remainer { },root { };auto bit count is qrt _ traits t::bitcount(n);for(size _ t I bit count;I 0;){ I-2;根1;根;余数2;余数| isqrt _ traits t::extractwobitsat(n,I);如果(root remainder) {余数-根;根;} else-root;}返回根1;} T需要支持、、前缀、前缀-、| uint8_t,还需要提供一个isqrt_traitsT来提取两个额外的操作。对于内置的无符号整数类型,其通用isqrt_traits如下:Template TypeName T Struct isqrt _ traits { static _ ass: : IS _ unsign: : value,泛型iSQRT只对无符号类型);//两个静态大小的倍数的位数_ T bit count(const T n){ T a(n);size _ t count 0;while(a 0){ a 2;计数2;}返回计数;} //提取i 1,I位静态uint 8 _ T extractwobitsat(const T n,size _ T I){ return static _ castuint 8 _ T((n I)3);} };在isqrt2的每次迭代中,我们通过移位得到两个比特,而在isqrt中,我们使用extractwobitsat(n,I)得到第1个和第1个比特。这个变化是因为可以直接从一个大整数中获取一个比特,而不需要复制另一个大整数进行移位运算。这里的BitCount()其实可以简单的返回siz: : Vector U中,这里U一般可以设置为uint32_t或者uint64_t,并添加十六进制流输出:template typename U class biguint {public: biguint(): v { 0 } { } biguint(STD :: initializ: v(init){ } biguint运算符(size _ t shift){ assert(shift unitBitCount);u in bits 0;for(auto x : v){ U outBits x(unitBitCount-shift);x(x shift)| in bits;inBits outBits} if(in bits)v . push _ back(in bits);返回* this} biguint运算符(size _ t shift){ assert(shift unitBitCount);u in bits 0;for(auto itr v . r begin();itr!();itr){ U outBits * itr(unitBitCount-shift);* itr(* itr shift)| in bits;inBits outBits} if(()0)v . pop _ back();返回* this} biguint运算符|(uint 8 _ t RHS){ v[0]| RHS;返回* this} biguint运算符-(const biguint RHS){ ass: 0;u以前的v[I];v[I]-r in borrow;inBorrow v[i]上一页1 : 0;} assert(in borrow 0);while(()1()0)v . pop _ back();返回* this} biguint运算符(){ for(auto x : v)if(x!0)返回* this五. push _ back(1);返回* this} biguint运算符- () { ass: v)if(x-!0)返回* this返回* this} bool运算符(const biguint RHS)const { if(()()){ for(auto I();I-0;)if (v[i] rhs.v[i])返回tru:e CHO 23-@ . com:e CHO 25-@ . come stream OS,const biguint x){ auto f(OS . flags());OS 0x std:: hex;for(auto itr x . v . r begin();itr!();itr)OS * itr;OS . flags(f);返回OS;} friend struct is qrt _ traitsbiguint;privat:静态常量size _ t unitBitCount siz:: vectoru v;};并为biguintU提供一个iSqrt _ Traits:Template TypeName ustrct iSqrt _ Traitsbiguintu { static size _ t bit count(const biguintU n)。{ r::itbitcount *(()-1)is qrt _ traitsu::bitcount(());}静态uint8 _ t extractTwoBitsAt(const biguintU n,size _ t I){ return static _ castuint 8 _ t((n . v[I/biguintu: unit count](I biguintu: unit count))3);} };我简单测了一下45765和50!int main(){//floor(SQRT(45765))213 STD : : Cout I SQRT 1(45765)STD : : : : cout isqrt 2(45765)std: : : : cout isqrtunsign: : endl;// 50!49 eebc 961 ed 279 b 02 B1 ef 4f 28d 19 a 84 f 5973 a1d 2c 7800000000000//楼层(sqrt(50!))899310 e 94 A8 b 185249821 ebc: : cout is qrt(biguintuit 32 _ t { 0x 00000000,0xd2c78000,0x4f5973a1,0xf28d19a8,0xb02b1ef4,0x961ed279,0x 49 eebc })std: echo 54--} output $ g-stdc 11-o isqrt isqrt . CPP ./isqrt 213 213 213 0x 899310 e 94 A8 b 185249821 ebce 7050!平方根(sqrt(50!))在十六进制匹配(知乎插入的网址有bug)。原代码在大整数平方根github。注意:还没有完全测试过。-更新一:点击@算出大海无边的暗示。,时间复杂度的顺序应该是——更新2之前有错误:isqrt0(),感谢@LOOP反馈。