您的位置:首页 > 编程语言 > C语言/C++

输入m和n,从1,2,3...n中找出和为m的组合

2015-07-29 10:57 405 查看
快到招聘季,从july100上面找了些题目练练手,写此文章也算是加深对这个题目的解题思路的理解,水平有限,如有考虑不周,欢迎指教。言归正传,我们来看看题目

题目:输入m和n,从1,2,3...n中找出和为m的组合

第一眼看到这个题目以为很简单,就是设置两个指针,分别从头部和尾部开始遍历,第一个指针x指向的值加上第二个指针y指向的值,如果*x+*y > m ,则--y,如果等于则输入这两个值并且++x;--y,否则++x,循环直到x>=y为止。但是一细想不对呀,题目要求的是组合,而上面的方法给出的是个数为2的和为m的组合,瞬间感觉题目有点难了,这该如何解决呢,陷入一阵沉思,这个组合的个数可能为1,2,3...m,想到用动态规划,但是具体该怎么做还是没头绪。有时候毫无头绪的时候从最简单的情况开始分析,会让你找到方向。假设f(m)是指求m的组合,则f(1)={1},f(2)={1+f(1),
2}, f(3)={1+f(2), 2+f(1), 3} ... f(m)={1+f(m-1), 2+f(m-2), ... m-1+f(1)}, 从中我们可以看出些端倪,f(m)中每个元素就是一个组合,而f(m-1)、f(m-2) ... f(1)分别包含的又是某个值下的组合,所以我在求f(m)的时候,f(1)、f(2) ... f(m-1) 的组合也要保存起来,我想到的数据结构是map<int, vector < vector<int> > >用键值对,key代表的是要求的某个组合的值,value则是该key下的组合(一个组合用vector<int>保存,多个组合的话就是vector
< vector<int> >)。这样求出的某个值的组合可能会出现重复的情况,所以我先对要插入的组合vector<int>排序,然后再对 vector< vector<int> > 去重。

代码如下:

#include <iostream>

#include <Windows.h> //调用system("pause")

#include <map>

#include <vector>

#include <algorithm>

using namespace std;

//两个同类型的容器可以比较大小

bool compare(const vector<int> &vec1, const vector<int> &vec2)

{
return vec1 == vec2 ? true : false;

}

bool sortCmp(const vector<int> &vec1, const vector<int> &vec2)

{
return vec1 < vec2 ? true : false;

}

int main()

{
int m=6, n=6;
//cin >> m >> n;
//key=1,2,3,...m
//value = 在该key下的组合
map<int, vector< vector<int> > > compose;

vector<int> one(1,1);
vector< vector<int> > oneCom(1, one);

        compose[1] = oneCom;
for (int i = 2; i <= m; i++)
{
for (int j=1; j < i; j++)
{
int k = i-j;
vector< vector<int> >::iterator iter = compose[k].begin();
while (iter != compose[k].end())
{
   vector<int> two((*iter).begin(), (*iter).end());
   two.push_back(j);
    sort(two.begin(), two.end()); //排序
   compose[i].push_back(two);
   two.clear();
    ++iter;
}
}
compose[i].push_back(vector<int>(1,i));
sort(compose[i].begin(), compose[i].end(), sortCmp);
vector <vector<int> > ::iterator index = unique(compose[i].begin(), compose[i].end(), compare);
compose[i].erase(index, compose[i].end());
}

vector< vector<int> >::iterator result = compose[m].begin();
for (; result != compose[m].end(); result++)
{
vector<int>::iterator  series = (*result).begin();
for (; series != (*result).end(); series++)
{
cout << *series << " ";
}
cout << endl;
}

system("pause");
return 0;

}

result:



题目没有说明一个组合中能不能重复出现某个值,这是能重复出现某个值得版本,如果要求不能重复出现某个值得话只要对上面的程序稍加修改就可以了。



心得:

通过做这个题目,让我这个菜鸟加深了对C++顺序容器vector,关联容器map的使用,并学习了泛型编程中sort、unique带条件的情况。天下无难事,只要肯钻研,柳暗花明就在眼前。这只是我对这个题目的想法,可能你有更好的方法,欢迎交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ STL