Algorithm 如何找到任何整数的乘法分区?

Algorithm 如何找到任何整数的乘法分区?,algorithm,combinatorics,discrete-mathematics,divide-and-conquer,Algorithm,Combinatorics,Discrete Mathematics,Divide And Conquer,我正在寻找一种有效的算法来计算任意给定整数的乘法分区。例如,12的此类分区的数量为4,即 12=12x1=4x3=2x2x3=2x6 我已经阅读了这方面的文章,但这并没有真正给我一个生成分区的算法(它只讨论了这样的分区的数量,老实说,这对我来说还不是很清楚!) 我正在研究的问题要求我计算非常大的数(>10亿)的乘法分区,因此我试图提出一种动态规划方法(这样,当较小的数本身是较大数的一个因子时,可以重新使用较小数的所有可能分区),但到目前为止,我不知道从哪里开始 任何想法/提示都将不胜感激-这不是

我正在寻找一种有效的算法来计算任意给定整数的乘法分区。例如,12的此类分区的数量为4,即

12=12x1=4x3=2x2x3=2x6

我已经阅读了这方面的文章,但这并没有真正给我一个生成分区的算法(它只讨论了这样的分区的数量,老实说,这对我来说还不是很清楚!)

我正在研究的问题要求我计算非常大的数(>10亿)的乘法分区,因此我试图提出一种动态规划方法(这样,当较小的数本身是较大数的一个因子时,可以重新使用较小数的所有可能分区),但到目前为止,我不知道从哪里开始


任何想法/提示都将不胜感激-这不是家庭作业问题,只是我试图解决的问题,因为它看起来很有趣

我要做的第一件事是得到这个数的素因子分解

从那里,我可以对每个因子子集进行排列,乘以迭代中剩余的因子

所以如果你取一个像24这样的数字,你会得到

2 * 2 * 2 * 3 // prime factorization
a   b   c   d
// round 1
2 * (2 * 2 * 3) a * bcd
2 * (2 * 2 * 3) b * acd (removed for being dup)
2 * (2 * 2 * 3) c * abd (removed for being dup)
3 * (2 * 2 * 2) d * abc
重复所有“轮数”(轮数是乘法第一个数中的因子数),在出现重复项时移除重复项

所以你最终会得到这样的结果

// assume we have the prime factorization 
// and a partition set to add to
for(int i = 1; i < factors.size; i++) {
    for(List<int> subset : factors.permutate(2)) {
        List<int> otherSubset = factors.copy().remove(subset);
        int subsetTotal = 1;
        for(int p : subset) subsetTotal *= p;
        int otherSubsetTotal = 1;
        for(int p : otherSubset) otherSubsetTotal *= p;
        // assume your partition excludes if it's a duplicate
        partition.add(new FactorSet(subsetTotal,otherSubsetTotal));
    }
}
//假设我们有素数分解
//以及要添加到的分区集
对于(int i=1;i
你为什么不找出所有能除以这个数的数,然后找出乘法加起来的数的排列

找到所有可以除以数字的数字需要O(n)

然后你可以排列这个集合,找到所有可能的集合,这个集合的乘法会给你这个数


一旦你找到了所有可能的数除以原始数的集合,你就可以对它们进行动态规划,找到将它们相乘得到原始数的一组数。

当然,首先要做的是找到这个数的素数分解,就像glowcoder说的那样。说

n = p^a * q^b * r^c * ...
然后

  • m=n/p^a

  • 对于乘法将与原始数相加的数字的
    0置换(置换?组合?我忘记了正确的单词),它应该是置换。@glowcoder:一些问题-对于一个有很多素数因子的足够大的数字,大部分工作将在识别和删除重复分区方面完成。我一直在寻找一种方法,在这一代人的成长过程中,克服这一点。还有,factors.permutate(2)的作用是什么?我在STL中没有找到任何与之对应的API,因此我想知道“2”参数的意义。@shan23-您可以进行一些优化,以减少其破坏性,但这是一个固有的昂贵操作。
    permutate(2)
    是一个输入错误-它应该是
    permutate(i)
    ,不,我不相信它在任何STL库中。这是一个函数的伪代码,该函数将返回一个值列表,每个值的大小
    i
    ,完成所有可能的子列表。“一旦您找到所有可能的数字集,然后您可以对它们进行动态编程”-我希望得到一个比“进行动态编程”更具体的提示:。例如,你能告诉我,在计算较大整数的分区时,我应该如何使用较小整数的分区吗?对于接近投票,理想情况下应该有某种解释,说明为什么你认为这需要关闭,以便OP可以纠正他/她的错误(如果有)。请唯一的投票人大声说出来好吗?没有任何解释的投票-总是喜欢那些!我错误地投了一票。我很抱歉。@Mods,有没有办法修改错误的投票结果?shan23,这真的不应该造成问题;这一问题还需要几票才能结束。如果真的发生了这种情况,我会尽快重新投票。我不知道Haskell,但我想你已经运行了你的代码-我很想知道大数字(比如1000000000)需要多少时间?当我最终在C++中编码我的解决方案时,它会给我一个想法。……作为一个疯狂的猜测,10的改进因素看起来不可能。这是一个非常好的答案(用时间)-让我在周末尝试C++,看看它是否变得更好。另外,还有一个相关的查询——当计算一个更大的数(其中一个因子是$n$)的分区时,如何利用$n$的分区?我想得到一系列数字n…m的分区,所以如果我能找到一种方法的话,这对我特别有用!由于分区的形状仅取决于素因子分解中的指数,我们还可以重用
    n
    的分区来生成
    m
    的分区,如果
    n
    不是
    m
    的因子,那么我们所需要的就是素因子分解的合适结构。例如,
    12=2^2*3^1
    ,因此我们可以重用12的分区来查找
    90=2^1*3^2*5^1
    的分区。我们只需要在12的分区中交换2和3,就可以得到18的分区,然后再加上5。如果您为
    p^k,p^a*q^b,p^a形式的数字存储分区*
    
    module MultiPart (multiplicativePartitions) where
    
    import Data.List (sort)
    import Math.NumberTheory.Primes (factorise)
    import Control.Arrow (first)
    
    multiplicativePartitions :: Integer -> [[Integer]]
    multiplicativePartitions n
        | n < 1     = []
        | n == 1    = [[]]
        | otherwise = map ((>>= uncurry (flip replicate)) . sort) . pfPartitions $ factorise n
    
    additivePartitions :: Int -> [[(Int,Int)]]
    additivePartitions 0 = [[]]
    additivePartitions n
        | n < 0     = []
        | otherwise = aParts n n
          where
            aParts :: Int -> Int -> [[(Int,Int)]]
            aParts 0 _ = [[]]
            aParts 1 m = [[(1,m)]]
            aParts k m = withK ++ aParts (k-1) m
              where
                withK = do
                    let q = m `quot` k
                    j <- [q,q-1 .. 1]
                    [(k,j):prt | let r = m - j*k, prt <- aParts (min (k-1) r) r]
    
    countedPartitions :: Int -> Int -> [[(Int,Int)]]
    countedPartitions 0     count = [[(0,count)]]
    countedPartitions quant count = cbParts quant quant count
      where
        prep _ 0 = id
        prep m j = ((m,j):)
        cbParts :: Int -> Int -> Int -> [[(Int,Int)]]
        cbParts q 0 c
            | q == 0    = if c == 0 then [[]] else [[(0,c)]]
            | otherwise = error "Oops"
        cbParts q 1 c
            | c < q     = []        -- should never happen
            | c == q    = [[(1,c)]]
            | otherwise = [[(1,q),(0,c-q)]]
        cbParts q m c = do
            let lo = max 0 $ q - c*(m-1)
                hi = q `quot` m
            j <- [lo .. hi]
            let r = q - j*m
                m' = min (m-1) r
            map (prep m j) $ cbParts r m' (c-j)
    
    primePowerPartitions :: Integer -> Int -> [[(Integer,Int)]]
    primePowerPartitions p e = map (map (first (p^))) $ additivePartitions e
    
    distOne :: Integer -> Int -> Integer -> Int -> [[(Integer,Int)]]
    distOne _ 0 d k = [[(d,k)]]
    distOne p e d k = do
        cap <- countedPartitions e k
        return $ [(p^i*d,m) | (i,m) <- cap]
    
    distribute :: Integer -> Int -> [(Integer,Int)] -> [[(Integer,Int)]]
    distribute _ 0 xs = [xs]
    distribute p e [(d,k)] = distOne p e d k
    distribute p e ((d,k):dks) = do
        j <- [0 .. e]
        dps <- distOne p j d k
        ys <- distribute p (e-j) dks
        return $ dps ++ ys
    distribute _ _ [] = []
    
    pfPartitions :: [(Integer,Int)] -> [[(Integer,Int)]]
    pfPartitions [] = [[]]
    pfPartitions [(p,e)] = primePowerPartitions p e
    pfPartitions ((p,e):pps) = do
        cop <- pfPartitions pps
        k <- [0 .. e]
        ppp <- primePowerPartitions p k
        mix <- distribute p (e-k) cop
        return (ppp ++ mix)
    
    Prelude MultiPart> length $ multiplicativePartitions $ 10^10
    59521
    (0.03 secs, 53535264 bytes)
    Prelude MultiPart> length $ multiplicativePartitions $ 10^11
    151958
    (0.11 secs, 125850200 bytes)
    Prelude MultiPart> length $ multiplicativePartitions $ 10^12
    379693
    (0.26 secs, 296844616 bytes)
    Prelude MultiPart> length $ multiplicativePartitions $ product [2 .. 10]
    70520
    (0.07 secs, 72786128 bytes)
    Prelude MultiPart> length $ multiplicativePartitions $ product [2 .. 11]
    425240
    (0.36 secs, 460094808 bytes)
    Prelude MultiPart> length $ multiplicativePartitions $ product [2 .. 12]
    2787810
    (2.06 secs, 2572962320 bytes)