把M个同样的宝石放在N个同样的盘子_C++实现

把M个同样的宝石放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(其中1,5,1和5,1,1代表同一种方法),用C++实现
注意最后是输出n行字符,不是算出来有几种分法。假设输入为7, 3
示例:
如输入7,3,输出为8行:
7,0,0
6,1,0
5,2,0
4,3,0
5,1,1
4,2,1
3,3,1
3,2,2

思路:
本题可以使用递归法,也是深度优先搜索,遍历到所有满足条件的分法,存入vector中,将其从大到小排序后,放到set里,利用set元素不重复的特点进行去重。有2点需要说明:
①之所以使用set而不是unordered_set,是因为set的元素是按照字典序排序的,方便输出结果时控制顺序。而unordered_set是按照哈希表的顺序排序的,肉眼看起来跟乱序一样。
②set的元素类型可以用vector,也可以将vector的元素都转化成string存,因为他们都有严格顺序。
③如果是用vector直接存入set中,那输出时可以选择逆序输出,这样就和例子给的“从大到小”的顺序一致了。

代码如下:

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <string>

using namespace std;

void generatePartitions(int gems, int plates, vector<int>& partitions, set<vector<int>>& uniquePartitions)
{
    if (plates == 1)
	{//分到最后一个盘子了
        partitions.push_back(gems);
		
		vector<int> tempPartitions = partitions;
		sort(tempPartitions.begin(), tempPartitions.end(), [](int a, int b){return a > b;});
        uniquePartitions.insert(tempPartitions);//将排序后的结果存入uniquePartitions中
        partitions.pop_back();//回溯
        return;
    }

    for (int i = 0; i <= gems; ++i) {
		
        partitions.push_back(i);
        generatePartitions(gems - i, plates - 1, partitions, uniquePartitions);//递归
        partitions.pop_back();//回溯
    }
}

int main() {
    int gems = 7;  // 宝石的数量
    int plates = 3;  // 盘子的数量

    vector<int> partitions;//每轮分宝石的方案
    set<vector<int>> uniquePartitions;//存所有可行方案的set
    generatePartitions(gems, plates, partitions, uniquePartitions);

    // 逆向打印set中的所有方案
    for (auto iter = uniquePartitions.rbegin(); iter != uniquePartitions.rend(); ++iter)
	{
        cout << (*iter)[0] << "," << (*iter)[1] << "," << (*iter)[2]  << endl;
    }

    return 0;
}

输出是:

7,0,0
6,1,0
5,2,0
5,1,1
4,3,0
4,2,1
3,3,1
3,2,2
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码到程攻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值