整数拆分问题的分析(dfs)

来源:互联网 发布:摇财树安全 知乎 编辑:程序博客网 时间:2024/05/10 21:52

在图书馆书上看到的一个题目,书上是用别的方法做的,我的第一感觉是用dfs,分析了一下,很有收获,总结下。

整数拆分问题,比如6可以拆分为:

6=66=5+16=4+26=4+1+16=3+36=3+2+16=3+1+1+16=2+2+26=2+2+1+16=2+1+1+1+16=1+1+1+1+1+1
有11种

我的想法是拆分序列可以递增或递减,上面的就是递减的,这种就是递增的

6=1+1+1+1+1+16=1+1+1+1+26=1+1+1+36=1+1+2+26=1+1+46=1+2+36=1+56=2+2+26=2+46=3+36=6

ok,这个思路的代码分别是:

void fun1(int n){//递减 if(n<0)return;if(n==0) ans++;int i;for(i=n;i>=1;i--){fun1(n-i);}}void fun2(int n){//递增if(n<0)return;if(n==0) ans++;int i;for(i=1;i<=n;i++){fun2(n-i);}}
这个n的意义是将整数n进行拆分,但是像上面的思路会产生重复,比如:4=2+1+1,4=1+2+1,还有其他类似的情况。

为了防止这类情况的发生,可以将结点值保存下来,传递到子结点,保证子结点的值小于其父结点,同理,递增的一样。

对应的代码:

void fun1(int n,int k){//递减 if(n<0)return;if(n==0) ans++;int i;for(i=k;i>=1;i--){fun1(n-i,i);}}void fun2(int n,int k){//递增if(n<0)return;if(n==0) ans++;int i;for(i=k;i<=n;i++){fun2(n-i,i);}}

这样就保证了结点的值始终小于(大于)其父结点,保证单调序列。

附上运行图片:


附上源代码:

#include <iostream>#include <vector>#include <algorithm>using namespace std;const int maxsize=100;int ans=0,m;vector<int> data;void print();void fun1(int n,int k){//递减 if(n<0)return;if(n==0) {ans++;print();}int i;for(i=k;i>=1;i--){data.push_back(i);fun1(n-i,i);for(vector<int>::iterator j=data.begin();j!=data.end();j++){if(*j==i){data.erase(j);break;}}}}void fun2(int n,int k){//递增if(n<0)return;if(n==0) {ans++;print();}int i;for(i=k;i<=n;i++){data.push_back(i);fun2(n-i,i);for(vector<int>::iterator j=data.begin();j!=data.end();j++){if(*j==i){data.erase(j);break;}}}}void print(){int i,count=0;cout<<m<<"=";cout<<data[0];for(i=1;i<data.size();i++){cout<<"+"<<data[i];}cout<<endl;}int main(){int i;cin>>m;cout<<"递减:"<<endl;fun1(m,m);ans=0;cout<<"递增:"<<endl;fun2(m,1);return 0;}


0 0
原创粉丝点击