将整数n分成k份(回溯)

/*
    Name: 将整数n分成k份(回溯) 
    Copyright: 
    Author:  巧若拙 
    Date: 16/12/18 13:25
    Description: 将整数n分成k份
将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。 
例如:n=7,k=3,下面三种分法被认为是相同的。 
1,1,5; 1,5,1; 5,1,1; 
问有多少种不同的分法。
     
算法1:回溯算法框架1:先处理递归出口(即终点),再枚举各种可能值,递归搜索下一层。 
算法2:回溯算法框架2:先枚举各种可能值,再判断是否到达终点,若到达终点则输出结果,否则递归搜索下一层。 
算法2的搜索深度比算法1要少一层,但是不如算法1结构清晰。
算法3:非递归算法:自定义栈模拟算法2的递归过程。
*/
#include<iostream>
#include<cmath>

using namespace std;

const int N = 10; //整数n范围 
int a[N+1] = {1}; //确保a[1]不小于1 
int s = 0;

void Print(int t);
void dfs1(int n, int k, int t); //框架1 
void dfs2(int n, int k, int t); //框架2 
void dfs3(int n, int k); //非递归算法 

int main()
{
    int n, k;
    cin >> n >> k;
    
    //dfs1(n, k, 1);
    //dfs2(n, k, 1);
    dfs3(n, k);
    
    cout << s << endl;
    
    return 0;
}

void Print(int t)
{
    for (int i=1; i<t; i++)
    {
        cout << a[i] << "+";
    }
    cout << a[t] << endl; 
}

void dfs1(int n, int k, int t) //框架1 
{
    if (t == k) //到达终点,输出结果 
    {
        a[t] = n;
        Print(t); 
        s++;
    }
    else
    {
        for (int i=a[t-1]; i<=n/(k-t+1); i++) //枚举各种可能值,生成一个非递减序列 
        {
            a[t] = i;
            dfs1(n-i, k, t+1); //搜索下一层 
        }
    }
}

void dfs2(int n, int k, int t)//框架2 
{
    for (int i=a[t-1]; i<=n/(k-t+1); i++) //枚举各种可能值,生成一个非递减序列 
    {
        if (t == k) //到达终点,输出结果 
        {
            a[t] = n;
            Print(t); 
            s++;
            break;
        }
        else
        {
            a[t] = i;
            dfs2(n-i, k, t+1); //搜索下一层 
        }
    }
}

void dfs3(int n, int k) //非递归算法 
{
    int t = 1;
    while (t >= 1)
    {
        while (++a[t] <= n/(k-t+1)) //枚举各种可能值,生成一个非递减序列 
        {
            if (a[t] >= a[t-1])   //满足条件 
            {
                if (t == k) //到达终点,输出结果 
                {
                    a[t] = n;
                    Print(t); 
                    s++;
                    break;
                }
                else
                {
                    n -= a[t];  //修改标记  
                    t++;  //搜索下一层 
                }
            }
        }
        a[t--] = 0; //回溯 
        n += a[t]; //恢复标记 
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
这道题目要求将整数 n 分成 k ,并且每不能为空,任意两不能相同(不考虑顺序),然后计算有多少不同的分法。 我们可以使用深度优先搜索(DFS)的方法来解决这个问题。 具体思路如下: 1. 定义一个递归函数 `dfs`,该函数负责进行深度优先搜索。 2. 在递归函数中,判断是否满足终止条件。如果已经分完了 k ,即 `cur == k`,那么得到了一合法的分法,进行相应的处理(如计数、输出等)。 3. 如果还没有分完 k ,遍历当前状态下的所有可能的选择。 - 从 1 到 n 之间选择一个数字作为当前的大小,记为 `i`。 - 如果当前大小 `i` 大于等于上一的大小 `prev`,则继续递归调用 `dfs`,将问题规模缩小。更新 `cur` 加 1,`sum` 加上当前选择的数字。 - 在递归调用后,需要进行回溯操作,将状态恢复到之前的状态,以便尝试其他的选择。 4. 在主函数中,首先读取输入的整数 n 和 k。 5. 调用 `dfs(0, 0, 0)` 开始深度优先搜索,并记录不同分法的个数。 6. 输出不同分法的个数。 以下是修改后的代码,逐行解释: ```cpp #include<iostream> using namespace std; int cnt = 0; void dfs(int cur, int prev, int sum, int n, int k) { if (cur == k) { if (sum == n) { cnt++; } return; } for (int i = prev + 1; i <= n; i++) { dfs(cur + 1, i, sum + i, n, k); } } int main() { int n, k; cin >> n >> k; dfs(0, 0, 0, n, k); cout << cnt << endl; return 0; } ``` 希望这个解答对你有帮助!如果还有其他问题,请随时提问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值