1. 程式人生 > >分蘋果(列舉加遞迴)

分蘋果(列舉加遞迴)

/*
描述:把M個同樣的蘋果放在N個同樣的盤子裡,允許有的盤子空著不放,問共有多少種不同的分法?(用K表示)5,1,1和1,5,1 是同一種分法。
輸入:第一行是測試資料的數目t(0 <= t <= 20)。以下每行均包含二個整數M和N,以空格分開。1<=M,N<=10。
輸出:對輸入的每組資料M和N,用一行輸出相應的K。
輸入例項:
1
7 3

輸出例項:8

*/

#include <iostream>
#include <fstream>
#include<algorithm>

using namespace std;

int Count;
int a[11];//a[i]表示第i個盤子分的蘋果個數
int sum;
int m,n;

int min(int x,int y)
{
    return x<=y?x:y;
}    

void Try(int j,int i)   //嘗試在剩餘了j個蘋果的情況下給第i個盤子分蘋果
{
    if(i>n) return ;
    for(int k=min(a[i-1],j);k>=1;k--)
    {
        a[i]=k; sum=sum+k;   //第i個盤子分k個蘋果,sum表示已分蘋果的總數
        if(sum==m)  //一種分法
        {
            Count++;   //分法數加1
        }
        else Try(j-k,i+1);
        sum=sum-k;    
    }    
}    
 
int main()
{
    int t;
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        cin>>m>>n;
        Count=0;
        if(n==1)  //一個盤子只有一種分法
        {
          Count=1;
          cout<<Count<<endl;
          continue;
        }    
        for(a[1]=m;a[1]>=1;a[1]--)
        {//列舉第一個盤子分配蘋果的個數
          sum=a[1];
          if(a[1]==m)
          {
              Count++;
          }
          Try(m-a[1],2); //在已知第一個盤子分完蘋果的情況下從第2個盤子開始分蘋果
        }  
        cout<<Count<<endl;
    }    
    return 0;
}

第二種方法:可計算放蘋果方案數也可以輸出每一種放法。

#include <stdio.h>
#include <stdlib.h>
int resu[20];
int f(int m,int n,int x)
{//m個蘋果,n個盤子,且第一個盤子至少放x個蘋果的分法數
    int sum=0;
    if(n==1)
    {
        resu[0]=m;//最後一個盤子放m個蘋果
        int j=0;
        while(resu[j]!=-1)  //輸出一種放蘋果方案
        {    printf("%d ",resu[j]);j++;}
        printf("\n");
        return 1; //如果只有一個盤子,分法數為1(遞迴出口)
        
    }    
    for(int i=x;i<=m/2;i++)  //第一個盤子可以放x~m/2個蘋果
    {
        resu[n-1]=i;
        if(m-i>=i) sum+=f(m-i,n-1,i);//保證後分配蘋果的盤子上蘋果數量大於等於前一個盤子蘋果數
    }
    return sum;
}

int main()

    int n;
    scanf("%d",&n);
    int a,b;     //蘋果數和盤子數
    while(n--)
    {
       scanf("%d%d",&a,&b);
       resu[b]=-1;
       printf("%d\n",f(a,b,0));
    }
   return 0;
}