组合-砝码问题

组合问题:从n个数里(互不相同)的取出m个,有多少种可能性?


//main.c

#include <iostream>
#include <map>
#include <vector>


using namespace std;


int min(int m, int n)
{
return m<n?m:n;
}


/************************************************************************/
/* 
**从n个里面取m个的取法
** 参数p用于记录每次取法中,标记哪些成员已被取出
**参数flag如果置位,表示p中为0的成员是被取出的
**参数flag如果未置位,表示p中为1的成员是被取出的
**myMap用来保存所有的组合结果
*/
/************************************************************************/
int combine(int n, int m, int *p, int flag, map<vector<int>, int> &myMap)
{
if(0 == n || 0 == m)
{
vector<int> vec;
for(int i = 0; i < n; i++)
{
if(p[i] && !flag)
{
//cout<<i<<" ";
vec.push_back(i);
}


else if(!p[i] && flag)
{
//cout<<i<<" ";
vec.push_back(i);
}
}
cout<<endl;

if(!myMap.count(vec))
myMap[vec] = 1;


return 1;
}


int count = 0;
for(int i =0; i < n; i++)
{
if(0 == p[i])
{
p[i] = 1;
count +=combine(n, m-1, p, flag, myMap);
p[i] = 0;
}

}


return count;
}


//表示从n个里面,取出m个的取法有多少种
int zuhe(int n, int m)
{
int *p = new int[n];
memset(p, 0, sizeof(int)*n);


int flag;
flag = m > (n-m) ? 1:0 ;


map<vector<int>, int> myMap;
int count = combine(n, min(m, n-m), p, flag, myMap);


delete []p;


return myMap.size();
}


前面已经实现了怎样计算从n个数里取出m个的可能性,现在再深入一点,有n个数,至少取出一个数,那么共有多少情况?

对上面的代码上又实现了一个函数:

//

//从n个元素的数组p里计算出所有的组合情况
int countAllCombine(int *p, int n)
{
int count = 0;
for(int i =1; i <= n; i++)
{
count += zuhe(n, i);
}


return count;
}


现在我们来解决一个有趣的问题,砝码问题。

有一组砝码,质量互不相同,问利用这组砝码,共能称出多少种质量不同的物品。

在前面的代码基础上又做了一些改进:

//

//所有的组合情况都保存在myMap里
void zuhe(int n, int m, map<vector<int>, int> &myMap)
{
int *p = new int[n];
memset(p, 0, sizeof(int)*n);


int flag;
flag = m > (n-m) ? 1:0 ;


int count = combine(n, min(m, n-m), p, flag, myMap);


delete []p;


//return myMap.size();
}


/**
**砝码问题
**有n个砝码,重量互不相同,共能称出多少种质量的物本
*/
int poiseWeight(int *p, int n)
{
map<vector<int>, int> myMap; //保存所有的组合情况
for(int i=1; i <= n; i++)
{
zuhe(n, i, myMap);
}


map<int, int> result; //保存所有能称的质量
map<vector<int>, int>::iterator map_itr = myMap.begin();
for(; map_itr != myMap.end(); map_itr++)
{
int weight = 0;


//遍历所有的组合情况,并计算出每一种组合的称重质量
vector<int>::const_iterator vec_itr = map_itr->first.begin();
for(; vec_itr != map_itr->first.end(); vec_itr++)
{
weight += p[*vec_itr];
}


//如果该所称的质量已经在结果里,则无需再加入
if(!result.count(weight))
{
result[weight] = 1;
cout<<weight<<" ";
}
}
cout<<endl;


return result.size();
}


int main()
{
int count = zuhe(5, 3);
cout<<"count is: "<<count<<endl;


int weight[] = {1, 2, 3, 4, 5};
count = poiseWeight(weight, sizeof(weight) /sizeof(int));
cout<<"poise weight is: "<<count<<endl;


return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值