左右间

行走在左右之间

博客园 首页 新随笔 联系 订阅 管理
问题分析:

假定N = 1, 则可能的整数集这能为{1}, 所以个数为1。

假定M = 1,N > 1, 则不可能有合适的整数集,所以个数为0。

假定M > N, 则结果集的个数和M = N的一样多, 因为不可能出现比N大的数。

假定M <= N, M > 1, N > 1, 此时我们有两种情况,结果集中包括M, 或者不包括。最终的数量为这两种情况的数量之和。


假定我们用F(N,M)来表示结果集的数量。则有如下表达式:

F(1,M) = 1; M为任意值.
F(N,1) = 0; N > 1.
F(N,M) = F(N,N); M > N.
F(N,M) = F(N - M,M - 1) + F(N,M - 1);M <= N, M > 1, N > 1.

一般有两种方式来解决这种问题,递归和动态规划。

递归方式:

        public static int GetPartitionCount2(int number, int maxElement)
        {
            if (number == 1)
                return 1;
            if (maxElement == 1)
                return 0;

            if (maxElement < number)
                return GetPartitionCount2(number - maxElement, maxElement - 1) + GetPartitionCount2(number, maxElement - 1);
            else
                return 1 + GetPartitionCount2(number, number - 1);
        }


动态规划:
public static int GetPartitionCount1(int number, int maxElement)
        {
            int[,] calculateTable = new int[number + 1, maxElement + 1];

            calculateTable[1, 1] = 1;

            for (int i = 2; i < number + 1; i++)
            {
                calculateTable[i, 1] = 0;
            }

            for (int i = 1; i < maxElement + 1; i++)
            {
                calculateTable[1, i] = 1;
            }

            for (int i = 2; i < maxElement + 1; i++)
            {
                for (int j = 2; j < number + 1; j++)
                {
                    if(i<j)
                        calculateTable[j, i] = calculateTable[j - i, i - 1] + calculateTable[j, i - 1];
                    else if(i>=j)
                        calculateTable[j, i] = 1 + calculateTable[j, j - 1];
                }
            }

            return calculateTable[number, maxElement];
        }

就递归方式而言,最大的不好之处就是递归次数太多,做了太多的冗余计算。

(N,M)          所需时间(ms)    
100,100        250
120,120         1281.3
140,140         6297
160,160         27484.7
180,180         110844.5
200,200         398417.4

相对而言,动态规划效率要高很多,不是一个数量级的。

(N,M)          所需时间(ms)    
1000,1000    46
2000,2000       187.5
3000,3000       593.8
4000,4000       1719.0
5000,5000       3172.3
6000,6000       5657.0
7000,7000    9345.1
8000,8000    13220.6
9000,9000    17736.9
10000,10000    22329.8

但是,在上面的动态规划算法中,有一个致命的地方就是数组分配,
int[,] calculateTable, 如果m,n较大,马上就内存溢出。
posted on 2009-01-15 17:41  左右间  阅读(659)  评论(0编辑  收藏  举报