• 成长轨迹58 【ACM算法之路 百炼poj.grids.cn】【递归】【1664:放苹果】


    题目http://poj.grids.cn/practice/1664


    真心是一道很经典很经典的题目,还是单独列出来

    离散数学学过划分,但是那是集合划分,这道题是整数划分。
    整数划分的思想如下:
    整数划分问题是将一个正整数n拆成一组数连加并等于n的形式,且这组数中的最大加数不大于n。
         如6的整数划分为
         6
         5 + 1
         4 + 2, 4 + 1 + 1
         3 + 3, 3 + 2 + 1, 3 + 1 + 1 + 1
         2 + 2 + 2, 2 + 2 + 1 + 1, 2 + 1 + 1 + 1 + 1
         1 + 1 + 1 + 1 + 1 + 1

    共11种。
    【dfs代码】

    View Code
     1 #include"iostream"
    2 using namespace std;
    3 int count=0;
    4 int M,m,n;
    5 void DFS(int k, int s,int t){
    6 if( s==n ){
    7 if(t==m) count++;
    8 return ;
    9 }
    10 int i;
    11 for(i=k;i>=0; i--){
    12 if( t + i <= m )
    13 {
    14 DFS(i, s+1, t+i);
    15 }
    16 else
    17 {
    18 continue;
    19 }
    20 }
    21 }
    22
    23 int main()
    24 {
    25 int i;
    26 scanf("%d",&M);
    27 while(M--)
    28 {
    29 count=0;
    30 scanf("%d %d",&m, &n);
    31 for(i=m;i>=0;i--)
    32 {
    33 DFS(i,1,i);
    34 }
    35 printf("%d\n",count);
    36 }
    37 return 0;
    38 }


    下面介绍一种通过递归方法得到一个正整数的划分数。

    递归函数的声明为 int deal(int m, int n);其中m为要划分的正整数,n是划分中的最大加数(当n > m时,最大加数为m),
         1 当m = 0 或 n = 1时,deal的值为1,可根据上例看出,只有一个划分1 或 1 + 1 + 1 + 1 + 1 + 1
         可用程序表示为if(n == 1 || m == 0) return 1;
        
         2 下面看一看m 和 n的关系。它们有三种关系
         (1) n > m
         在整数划分中实际上最大加数不能大于m,因此在这种情况可以等价为deal(m, m);
         可用程序表示为if(n > m) return deal(m, m);
         (2) n < m     这是最一般的情况,在划分的大多数时都是这种情况。
         从上例可以看出,设n = 4,那deal(6, 4)的值是最大加数小于4划分数和整数2的划分数的和。
         即 deal(6,4) = deal(6,3) + deal(2,4)
         因此,此时deal(n, m)可表示为deal(m, n - 1) + deal(m - n, n)
         (3) m = n
         这种情况可用递归表示为deal(m, n - 1) + 1,从以上例子中可以看出,就是最大加数为6和小于6的划分之和
         用程序表示为if(m == n) return (deal(m, n - 1) + 1);
         我们发现其实也可以满足上面(2)所推导的公式

    按照整数划分的思想,将一个整数划分为若干(x<=m) 整数,按由大到小逐级递减的顺序排列,  这样保证了不会出现 5,1,1 和 1,5,1 这种相同的情况,根据这样的思路来建立一个递归关系。

    【ac代码】

     1 #include <stdio.h>
    2 #include <stdlib.h>
    3
    4 int deal(int m,int n)
    5 {
    6 if(m==0||n==1)
    7 return 1;
    8 else if(n>m) return deal(m,m);
    9 else
    10 return deal(m,n-1)+deal(m-n,n);
    11 }
    12
    13 int main()
    14 {
    15 int t;
    16 scanf("%d",&t);
    17 for(int i=0;i<t;i++)
    18 {
    19 int m,n;
    20 scanf("%d %d",&m,&n);
    21 printf("%d\n",deal(m,n));
    22 }
    23 return 0;
    24 }
  • 相关阅读:
    c#生成图片验证码
    关于Aspcms如何嵌入整个网站,以及网站导航所指向页面的内容显示
    web 验证控件
    MVC Link连接数据库增删改查方法的不同写法
    Mvc 翻页查询,代码很有用
    MVC添加分布视图做唯一验证
    MVc路由查询,路由到底有什么作用呢??
    MVC添加动态视图的参考代码。重点是添加部分视图的使用方法,非常有用的代码!!!!!!!!!!!!!!
    tyvj P1209
    bzoj 1051: [HAOI2006]受欢迎的牛 tarjan缩点
  • 原文地址:https://www.cnblogs.com/zeedmood/p/2367808.html
Copyright © 2020-2023  润新知