数据结构和算法:圣诞老人分礼物

内卷之源:

暂无

题目描述:

 * 圣诞节到了,城堡里有k个小朋友,圣诞老人魔法口袋里带了n件无差别的小礼物。
 * 请帮圣诞老人处理:将n个无差别的礼物分给k个小朋友的分法问题。
 * 
 * 输入描述:
 *     仅一行,包含2个整数 n(0<=n<=10) 和 k(1<=k<=10),n表示礼物的数量,k表示小朋友的数量
 * 输出描述:
 *     第一行输出分法总数t
 *     后续t行依次列出每种分法:每件礼物用字符‘*’(ascii码为42)表示,用字符‘|’(ascii码为124)分隔小朋友。具体输出和顺序请参考示例。

测试用例:

 * 示例一:
 *     输入 3 2
 *     输出 4
 *          ***|  //给第一个小朋友分3件,给第二个小朋友分0件
 *          **|*  //给第一个小朋友分2件,给第二个小朋友分1件
 *          *|**  //给第一个小朋友分1件,给第二个小朋友分2件
 *          |***  //给第一个小朋友分0件,给第二个小朋友分3件
 * 示例二:
 *     输入 4 3
 *     输出 15
 *          ****||  //给第一个小朋友分4件,给第二个小朋友分0件,给第三个小朋友分0件
 *          ***|*|  //给第一个小朋友分3件,给第二个小朋友分1件,给第三个小朋友分0件
 *          ***||*  //给第一个小朋友分3件,给第二个小朋友分0件,给第三个小朋友分1件
 *          **|**|  //给第一个小朋友分2件,给第二个小朋友分2件,给第三个小朋友分0件
 *          **|*|*  //给第一个小朋友分2件,给第二个小朋友分1件,给第三个小朋友分1件
 *          **||**  //给第一个小朋友分2件,给第二个小朋友分0件,给第三个小朋友分2件
 *          *|***|  //给第一个小朋友分1件,给第二个小朋友分3件,给第三个小朋友分0件
 *          *|**|*  //给第一个小朋友分1件,给第二个小朋友分2件,给第三个小朋友分1件
 *          *|*|**  //给第一个小朋友分1件,给第二个小朋友分1件,给第三个小朋友分2件
 *          *||***  //给第一个小朋友分1件,给第二个小朋友分0件,给第三个小朋友分3件
 *          |****|  //给第一个小朋友分0件,给第二个小朋友分4件,给第三个小朋友分0件
 *          |***|*  //给第一个小朋友分0件,给第二个小朋友分3件,给第三个小朋友分1件
 *          |**|**  //给第一个小朋友分0件,给第二个小朋友分2件,给第三个小朋友分2件
 *          |*|***  //给第一个小朋友分0件,给第二个小朋友分1件,给第三个小朋友分3件
 *          ||****  //给第一个小朋友分0件,给第二个小朋友分0件,给第三个小朋友分4件

思路分析:

 * 根据输出格式可知,第一个小朋友的礼物数量按总数递减。第(k-1)个小朋友的礼物数量每次是基于分给第(k-2)个小朋友剩余的数量递减(显然需使用dfs)。前面所有小朋友分完后剩余的全分给最后一个小朋友。
 * 另可以归纳出的是:
      (1)以字符串输出具体分法,字符串长度固定是(n+k-1),其中字符‘*’的个数为(n),字符‘|’的个数为(k-1)。
      (2)输入的n可为0,k可为1,此时分法均只有一种。(该情形一般dfs应该涵盖进去)

编程实现(C++):

/*
 ************************************************************
 * @author    SLF
 * @version	  V1.0.0
 * @date      xx-xx-2020
 ************************************************************
 */

#include <iostream>
#include <string>
#include <vector>

using namespace::std;

void dfs(vector<string> &out, string method, const int &LEN, const int &n, const int &k, const int &index);

int main(void)
{
    int n, k;
    cin >> n >> k;

    // if (0 == n)
    // {//礼物数量为0
    //     cout << 1 << endl;
    //     for (int i = k-1; 0 < i; ++i)
    //     {//当k=1时是否该输出字符'|' ?
    //         cout << '|';
    //     }
    //     cout << endl;
    //     return 0;
    // }
    // if (1 == k)
    // {//人数为1
    //     cout << 1 << endl;
    //     for (; 0 < n; --n)
    //     {
    //         cout << '*';
    //     }
    //     cout << endl;
    //     return 0;
    // }

    const int LEN = n + k -1;
    vector<string> out;

    dfs(out, "", LEN, n, k-1, 0);

    cout << out.size() << endl;
    for (const auto &str : out)
    {
        cout << str << endl;
    }

    return 0;
}

//第二个形参不能使用引用
void dfs(vector<string> &out, string method, const int &LEN, const int &n, const int &k, const int &index)
{
    if (LEN == index)
    {
        out.push_back(method);
        return;
    }

    if (0 < n)
    {
        dfs(out, method + '*', LEN, n -1, k, index +1); // method + '*' 并不会改变本层的method字符串,只会改变下一层
    }
    
    if (0 < k)
    {
        dfs(out, method + '|', LEN, n, k -1, index +1); // method + '|' 并不会改变本层的method字符串,只会改变下一层
    }
}

  

郑重提示:①解题思路非最优,覆盖条件可能不全,仅供练习参考。

                  ②若有更佳思路或疑问,可在评论区留言相互讨论,不亦乐乎。

                  ③本文不允许转载,若认可本文,可点赞收藏关注。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值