关闭

动态规划问题详解(二)

标签: 动态规划
608人阅读 评论(0) 收藏 举报
分类:

  在动态规则问题详解(一)中,我们用1,3,5三个硬币,求用最少的硬币组成11元的问题。这一节,我们来讨论一个复杂一点的问题。这个问题,曾经是某公司的面试题。

   有从1-N个连接的整数,把1-N个整个划分为二个相等的集合,问有几种划分的方法。

       如  {1,2,3},则有{1,2}和{3},只有一种划分方法。

       如{1,2,3,4,5,6,7} 则有

 {1,6,7} and {2,3,4,5} {注 1+6+7=2+3+4+5}
{2,5,7} and {1,3,4,6}
{3,4,7} and {1,2,5,6}
{1,2,4,7} and {3,5,6}

这四种组合,编写程序,输入N,输入有几种划分的组合数。
如输入3,则输出1
输入7,则输出4
这个问题如何求解呢?
我们先分析,1-N个整数,和是多少? 根据等差数列的公式,我们得到 s=n*(1+n)/2,题目中要求把1-N划分为两个相等的集合,那么,s必须是偶数。 s%2 =0 . 如果s为奇数,则直接返回0.如果s为偶数,则,问题转化为,从1-N中取前i个数,使它们的和为s/2的组合。我们设d[i][j]为集合组和的个数,其中j为前i个数的和。那么,d[i][j]的状态方程如何写呢?
  d[i][j]为前i个数的和,按照动态规划的思想,d[i][j]的状态,只和i-1个数的状态有关。第i个数,要么在集合中,要么不在集合中(有人要问了,不是所有的数都要在集合中么?是的,共有两个集合,我们只拿其中一个集合来思考)
如果第i个数,在集合中,则第i-1个数的和为j.  d[i][j]=d[i-1][j].如果第i个数在集合中,则前i-1个数的和,为j-i.  d[i][j]=d[i-1][j-i]。
现在d[i][j]有两种情况,我们如何处理呢?之前我说过,本来共有2个集合,但为了思考的方便,我们只考虑了一个集合的情况.第i个数,要么在第一个集合中,要么在第二个集合中。
如{1,2,3} 可以划分成{1,2}及{3} 也可以划分为{3}及{1,2},虽然在本题中,这两种情况只算一种。但这个对我们后面结果数除以2的理解是有帮助的。
我们把这两种情况相加,然后除以2。
d[i][j]=d[i-1][j]+d[i-1][j-i]
有了这个状态转移方程,我们就可以很方便的写出代码了。


#include <stdio.h>
void main()
{
  int N=3;
  int way = divide(N);
  printf("%d\n", way);
}

int divide(int N)
{
  int d[1024]={0};
  int total=N*(N+1)/4;
  if (total*2 % 2)
  {
    return 0;
  }
  int i;
  int j;
  d[0]=1;
  for (i=1;i<=N;i++)
  {
    for (j=total;j>=i;j--)
    {
      d[j]= d[j] + d[j-i];
    }
  }
  return d[total]/2;
}



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:111652次
    • 积分:2704
    • 等级:
    • 排名:第13380名
    • 原创:161篇
    • 转载:3篇
    • 译文:0篇
    • 评论:40条
    文章分类
    最新评论