zoukankan      html  css  js  c++  java
  • poj1664 放苹果(DPorDFS)&&系列突破(整数划分)

    poj1664放苹果
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 33661   Accepted: 20824

    Description

    把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

    Input

    第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。

    Output

    对输入的每组数据M和N,用一行输出相应的K。

    Sample Input

    1
    7 3
    

    Sample Output

    8





    关键在于找到放的递推关系,要达到不重不露才可!
    递推关系就是,对于将n个苹果放在m个盘子里,因为可以有空盘子,
    所以会出现两种情况:一:没空盘子出现;二:有空盘子出现
    对于一显然每个盘子都至少含有一个苹果,所以此时dp[n][m]=dp[n-m][m];
    对于二,dp[n][m]=dp[n][m-1];
    最后注意dp数组的初始化

    之所以二考虑了所有情况:
    假设将5个果子放入3个盘子,在j==2时就已经考虑过了一个盘子是空的情况,所以j==3时考虑一个空盘子的情况也包含了两个都是空的情况

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
    int n,m,i,j,k,dp[105][105];
    int t;memset(dp,0,sizeof(dp));

    for(i=0;i<=100;++i) dp[0][i]=1;
    for(i=1;i<=100;++i)
    for(j=1;j<=100;++j)
    dp[i][j]=dp[i][j-1]+dp[i-j][j];
    cin>>t;
    while(t--){
    cin>>n>>m;
    cout<<dp[n][m]<<endl;
    }

    return 0;
    }

    递归姿势:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;

    int solve(int n,int m)
    {
    if(n == 1 || m == 1 || n == 0)
    return 1;
    if(n<m)
    return solve(n,n);
    else
    return solve(n,m-1)+solve(n-m,m);
    }

    int main()
    {
    int t,n,m;
    scanf("%d",&t);
    while(t--)
    {
    scanf("%d%d",&n,&m);
    printf("%d ",solve(n,m));
    }

    return 0;
    }

    由此题引出相似题目,整数划分,求一个整数可以被划分为多少种不同的整数的和

    例如:
     如n==6的整数划分为(要求所有的数都小于n)
        
        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种。

    仔细想想和放苹果类似,只不过是将n个果子放入n个盘子里!

    #include<bits/stdc++.h>
    using namespace std;
    int solve(int n,int m)
    {
    if(n==0||m==1||n==1) return 1;
    if(n>=m)
    return solve(n-m,m)+solve(n,m-1);
    else return solve(n,m-1);
    }
    int main()
    {
    int n,m;
    while(cin>>n) cout<<solve(n,n)<<endl;
    return 0;
    }

    将正整数划分成连续的正整数之和
    如15可以划分成4种连续整数相加的形式:
    15
    7 8
    4 5 6
    1 2 3 4 5

        首先考虑一般的形式,设n为被划分的正整数,x为划分后最小的整数,如果n有一种划分,那么
    结果就是x,如果有两种划分,就是x和x x + 1, 如果有m种划分,就是 x 、x x + 1 、 x x + 1 x + 2 、... 、x x + 1 x + 2 ... x + m - 1
    将每一个结果相加得到一个公式(i * x + i * (i - 1) / 2) = n,i为当前划分后相加的正整数个数。
    满足条件的划分就是使x为正整数的所有情况。
    如上例,当i = 1时,即划分成一个正整数时,x = 15, 当i = 2时, x = 7。
    当x = 3时,x = 4, 当x = 4时,4/9,不是正整数,因此,15不可能划分成4个正整数相加。
    当x = 5时,x = 1。

        这里还有一个问题,这个i的最大值是多少?不过有一点可以肯定,它一定比n小。我们可以做一个假设,
    假设n可以拆成最小值为1的划分,如上例中的1 2 3 4 5。这是n的最大数目的划分。如果不满足这个假设,
    那么 i 一定比这个划分中的正整数个数小。因此可以得到这样一个公式i * (i + 1) / 2 <= n,即当i满足
    这个公式时n才可能被划分。

    综合上述,源程序如下

    int split1(int n)
    {
        int i, j, m = 0, x, t1, t2;
       // 在这里i + 1之所以变为i - 1,是因为i * (i - 1) / 2这个式子在下面多次用到,
      // 为了避免重复计算,因此将这个值计算完后保存在t1中。并且将<= 号变为了<号。
        for(i = 1; (t1 = i * (i - 1) / 2) < n; i++) 
        {
            t2 = (n - t1);
            x =  t2 / i;
            if(x <= 0) break;
            if((n - t1) % i == 0)
            {
                printf("%d ", x);
                for(j = 1; j < i; j++)
                    printf("%d ", x + j);
                printf(" ");
                m++;
            }
        }
        return m;
    }
  • 相关阅读:
    Goflyway
    amd 阉割理论
    wget命令下载页面里所有资源文件
    linux fpcup-Lazarus_fpcupdeluxe TEncoding 乱码
    Error: (lazbuild) 不能加载包 fpcupdeluxe 手工干预卸载问题模块
    集合 数据 指针方法操作集合
    cmake windows pthread
    4 bit all 15
    Parser b2c
    Offline Explorer 规则
  • 原文地址:https://www.cnblogs.com/zzqc/p/6681878.html
Copyright © 2011-2022 走看看