把数字拆分成2的幂的和

问题:

任何数都能分解成2的幂,比如

7=1+1+1+1+1+1+1

=1+1+1+1+1+2

=1+1+1+2+2

=1+2+2+2

=1+1+1+4

=1+2+4

共有6种分解方式,设f(n)为任意正整数可能分解总数,比如f(7)=6

写个算法,输入数,求出其分解的总数。

思路:

先按照树形结构,把一个数可能的2的幂的子数记录下来,比如7拆分成7个1,3个2,1个4。从高到底遍历所有可能的搭配。

import math
import copy  

def get_distribute_for_number(number):
    distribute = {}
    distribute[0] = number
    for i in range(0, int(math.log(number, 2) + 1)):
        if i not in distribute:
            break
        count_i = distribute[i]
        while count_i >= 2:
            count_i -= 2
            if i + 1 not in distribute:
                distribute[i + 1] = 0
            distribute[i + 1] += 1
    return distribute  

 def count_by_distribute(distribute, number, parent_expr):
     if number == 0:
         print("expr : %s"%parent_expr[:-3])
         return 1
     max_leaf = len(distribute) - 1
     if max_leaf == 0:
         print("expr : %s"%(parent_expr + " 1 * %d"%number))
         return 1
     curr_distribute = copy.copy(distribute)
     max_leaf_value = 2 ** max_leaf
     max_leaf_num = curr_distribute.pop(max_leaf)
     count = 0
     for i in range(0, max_leaf_num + 1):
         left = number - max_leaf_value * i
         expr = parent_expr
         expr += "%d * %d"%(max_leaf_value, i)
         expr += " + "
         if left < 0:
             break
         count_left = count_by_distribute(curr_distribute, left, expr)
         count += count_left
         #print("current distribute is ")
         #print(curr_distribute)
         #print("kept %d leaves of %d"%(i, max_leaf_value))
         #print("distributing num for %d is %d"%(left, count_left))
     return count  

 number = input("Input Number:")
 distribute = get_distribute_for_number(number)
 print("Distribute for num is")
 print(distribute)
 count = count_by_distribute(distribute, number, "")
 print("Number %d can be distributed by %d ways"%(number, count))  
时间: 2024-10-11 01:22:24

把数字拆分成2的幂的和的相关文章

找出不小于给定数字的最小2的幂值

2017/3/13 12:59:41 看JDK源码,在HashMap类中发现了一个可以很好解决这个问题的方法. 问题描述: 假设给定 14,输出16:给定16,也输出16:给定17,输出32.输出满足给定数字的最小2的幂值 算法: int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; # 001XXXXX --> 0011XXXX n |= n >>> 2; # 0011XXXX --> 001

POJ 2229-Sumsets(把n拆分为2的幂相加的拆分种数)

题目地址:POJ 2229 题意:给定一个正整数,求有多少种方法把它写成若干个2幂次的和 思路:可以用递推,对于一个整数n,分为奇数和偶数,我们应该分情况讨论. 1.如果为奇数,那么在这个表示中一定含有一个1,把这个1减去,就是n-1 即dp[n]=dp[n-1]. 2.如果为偶数,那么也分两种情况,有1和没1.对于有1的情况可以直接拆出两个1,然后变为n-2的情况.对于没有1的情况可以直接将其转化为n/2,因为n拆分出所有的数字都是2的倍数,只需要将每种拆分结果中的数字都除以2就会与n/2的一

poj 2100 尺取法 一个数字拆成连续数字平方和

题意:将一个数拆成若干个连续数字的平方和. 用尺取法枚举区间,复杂度为O(n),时限10s,3s多ac. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cmath> 5 using namespace std; 6 7 const int N = 100; 8 9 struct Node 10 { 11 int from, to; 12 } node[N]

bzoj1297 [SCOI2009]迷路——拆点+矩阵快速幂

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1297 一看感觉是矩阵快速幂之类的,但边权不好处理啊: 普通的矩阵快速幂只能处理边权为1的,所以想办法把边权处理成1: 仔细一看还有一个条件是边权小于10: 所以拆点!把一个点拆成10个点表示到它不同的距离,那么和它相连的那些点就可以跟某个距离的点连边权为1的边: 虽然没有自己想出来,不过1A还是极好的!(因为太简单了) 代码如下: #include<iostream> #include&

mysql 大表拆分成csv导出

最近公司有一个几千万行的大表需要按照城市的id字段拆分成不同的csv文件. 写了一个自动化的shell脚本 在/home/hdh 下面 linux-xud0:/home/hdh # lltotal 16-rwxrwxrwx 1 root root 902 Dec 28 07:47 cf.sh-rwxrwxrwx 1 root root 6 Dec 28 07:47 id_1.txt-rwxrwxrwx 1 root root 6 Dec 27 20:00 log vim  cf.sh #!/bi

C#用int的0--31位表示32个bool值,int拆分成bool数组

使用位运算,直接上代码 public void IntToBoolArray() { bool[] bArray = new bool[32]; int inputNum = 3; int endNum; for(int i= 0;i<32;i++) { endNum = 1 << i; if(endNum == (endNum & inputNum)) { bArray[i] = true; }else { bArray[i] = false; } Debug.Log(bArr

[Introduction to programming in Java 笔记] 1.3.7 Converting to binary 十进制到二进制的转换

public class Binary { public static void main(String[] args) { // Print binary representation of N. int N = Integer.parseInt(args[0]); int v = 1; while(v <= N/2) v = 2*v; // Now v is the largest power of 2 <= N. int n = N; // current excess while (v

题目1084:整数拆分 (递推)

题意: 问一个数拆分成2的幂的和的方法数有多少种. 我是先通过找列举前面的找规律 n   种数 1    1 2    2 3    2 4    4 5    4 6    6 7    6 8    10 9    10 10   14 …… 1 #include<stdio.h> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib>

九度oj 题目1455:珍惜现在,感恩生活

题目描述: 为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买.请问:你用有限的资金最多能采购多少公斤粮食呢? 输入: 输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h&