• Luogu P1025 数的划分(递推 DP DFS)


     P1025 数的划分

    题目描述

    将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

    例如:n=7,k=3,下面三种分法被认为是相同的。

    1,1,5; 1,5,1; 5,1,1;

    问有多少种不同的分法。

    输入输出格式

    输入格式:

    n,k (6<n<=200,2<=k<=6)

    输出格式:

    一个整数,即不同的分法。

    输入输出样例

    输入样例#1:
    7 3
    
    输出样例#1:
    4
    

    说明

    四种分法为:1,1,5;1,2,4;1,3,3;2,2,3;

    noip2001年提高组第二题

      这道题对于我来说是一道有难度的题((´-_-)-_-)-_-)

      有三种思路,递推,DP,爆搜(dfs骗分神器)!

      AC①:dfs (24ms)

      

     1 #include <cstdio>
     2 
     3 int ans, n, k;
     4 
     5 // left表示还有多大数字没分
     6 // num表示还需分成几份
     7 // last表示上次分的数字是多少
     8 void dfs(int left, int num, int last)
     9 {    //条件
    10     if(num == 1)
    11     {
    12         ans++;
    13         return;
    14     }
    15     else
    16     {    //为什么是i = last  因为要避免分的重复 这样就能从小到大以次分(剪枝)
    17         //为什么i<=left/num 因为要保证后面的几份也能分到一个数
    18         for(int i=last; i<= left/num; i++)
    19             dfs(left-i, num-1, i);
    20     }
    21 }
    22 
    23 int main()
    24 {
    25     scanf("%d%d", &n, &k);
    26     //把n分成k份 从1开始分
    27     dfs(n, k, 1);
    28     printf("%d", ans);
    29     return 0;
    30 }

      第二种方法是递推

      这里要感谢DoubleCakes大大的 http://blog.csdn.net/u013174702/article/details/45620723

      把n看成是n个小球,k看成是k个盒子

      那么题目就变成了把n小球放到k个盒子,且每个盒子都至少有1个小球的问题。

      那么把n个小球放到k个盒子里的情况总数 = 1.至少有1个盒子放1个小球的情况总数 + 2.每个盒子都有多于1个小球的情况总数

      那么这里 1 相当于 把n-1个小球放到k-1个盒子里的情况总数

      2 相当于 把n-k个小球放到k个盒子里的情况总数

      到了这里就可以发现是递推咯。

      公式为 f(n,k) = f(n-1,k-1) + f(n-k,k)

      你说n<k时候? 请看代码

      AC②: 递推 (32ms)

     1 #include <cstdio>
     2 
     3 int ss(int n, int k)
     4 {
     5     if(n < k) return 0;    //如果n<k 肯定不可能每个盒子都有
     6     if(n == k) return 1;//盒子和小球数相等 只有一种方案 每个盒子里一个小球
     7     if(k == 1) return 1;//盒子只有一个时候 把剩下小球都放进去
     8     return ss(n-1, k-1) + ss(n-k, k);
     9 }
    10 
    11 int main()
    12 {
    13     int n, k;
    14     scanf("%d%d", &n, &k);
    15     printf("%d", ss(n, k));
    16     return 0;
    17 }

      第三种方法是DP

      其实理解了递推,那么就能理解dp了。

      方程为f[i][j] = f[i-1][j-1] + f[i-j][j]

      边界 f[0][0] = 1

      那么还有不懂就看代码吧

      AC⑨: dp(0ms dp大法好)

     1 #include <cstdio>
     2 
     3 int f[205][10];
     4 //f[n][k]表示将n分成k份的方案总数
     5 int main()
     6 {
     7     int n, k;
     8     scanf("%d%d", &n, &k);
     9     f[0][0] = 1;
    10     for(int i=1; i<=n; i++)
    11     {
    12         // j<=i保证i-j>=0   要记得还有 j<=k
    13         for(int j=1; j<=i && j<=k; j++)
    14         {
    15             f[i][j] = f[i-1][j-1] + f[i-j][j];
    16         }
    17     }
    18     printf("%d", f[n][k]);
    19     return 0;
    20 }
  • 相关阅读:
    数据库中 dbo是什么意思
    常用的设计模式 介绍
    ReferenceEquals和 == 和equals()的比较
    IOC 控制反转模式
    集群和负载均衡
    数据库 读写分离
    C# 中using的几个用途
    WCF ABC
    SQL Server数据库性能优化(三)之 硬件瓶颈分析
    SQL Server数据库性能优化(二)之 索引优化
  • 原文地址:https://www.cnblogs.com/yBaka/p/7391293.html
Copyright © 2020-2023  润新知