问题是这样的: 如何把一个自然数分割成M部分, 每一部分都是另一个自然数的N次方. 比如,如何把81分解成三个数的平方. 答案有三个: 81=64+16+1, 81=36+36+9, 81=49+16+16. 如何把7分成四个数, 答案也是三个, 4-1-1-1, 3-2-1-1, 2-2-2-1.
这个题使用递归算法来做不难, 我在学习模板编程的时候把它作为一道练习题来做的, 姑且也放在这里凑个数吧.
程序中主要是一个'template<int M, int N=1> Class Split'类, 用来把一个数分解为M个数的N次方,其他没什么太多需要解释的了, 下面给出完整程序, 其中还有一些注释, 如果有兴趣请自己看吧.
//
// Author: dgu
// Email: gdyxgzy@hotmail.com
//
#include <iostream>
#include <vector>
using namespace std;
// to see if an integer can be splitted into M parts, each part is an integer's N-th order
template<int M, int N=1>
class Split
{
int num;
vector<vector<int> > split(int m, int n, int start)
{
vector<vector<int> > result;
if(m<n || n<=0)
return result;
if(n==1)
{
if(IsRoot(m)==true)
result.push_back(vector<int>(1, m));
return result;
}
for(int i=start; i<=m/n; ++i)
{
if(IsRoot(i)==false)
continue;
vector<vector<int> > sub_split = split(m-i, n-1, i);
for(int j=0; j<sub_split.size(); ++j)
{
vector<int> temp = sub_split[j];
temp.push_back(i);
result.push_back(temp);
}
}
return result;
};
bool IsRoot(int x)
{
int low=1, high=x;
while(low<=high)
{
int middle = (low+high)/2;
int temp=1;
//
//Be careful of integer overflow if you do a high N!
//For example, if you do N=5, and x=33044(1, 2, 3, 8) or x=17083(1, 2, 3, 7),
//if you don't check integer overflow, it will report not found.
//So, you have to use 'temp<=x && i<N' instead of simply using 'i<N'.
//
for(int i=0; temp<=x && i<N; ++i)
temp *= middle;
if(temp>x)
high = middle-1;
else if(temp==x)
return true;
else
low = middle+1;
}
return false;
};
public:
Split() : num(1) {};
Split(int x) : num(x) {};
vector<vector<int> > operator()()
{
if(num<=1)
{
cout<<"invalid input, must be greater than 1."<<endl;
return vector<vector<int> >();
}
else
return split(num, M, 0);
}
vector<vector<int> > operator()(int x)
{
if(x<=1)
{
cout<<"invalid input, must be greater than 1."<<endl;
return vector<vector<int> >();
}
else
return split(x, M, 0);
};
};
int main()
{
int number;
vector<vector<int> > result;
// to see if 81 can be splitted into 4 integer's square
number = 81;
result = Split<3,2>(number)();
if(result.size() >0)
{
cout<<number<<" can be splitted as: "<<endl;
for(int i=0; i<result.size(); ++i)
{
vector<int> temp = result[i];
for(int j=0; j<temp.size(); ++j)
cout<<temp[j]<<',';
cout<<endl;
}
cout<<endl;
}
else
cout<<"No solution for "<<number<<"."<<endl;
number = 33044;
//to see if 33044 can be splitted into 4 integer's 5-th power
result = Split<4,5>(number)();
if(result.size() >0)
{
cout<<number<<" can be splitted as: "<<endl;
for(int i=0; i<result.size(); ++i)
{
vector<int> temp = result[i];
for(int j=0; j<temp.size(); ++j)
cout<<temp[j]<<',';
cout<<endl;
}
cout<<endl;
}
else
cout<<"No solution for "<<number<<"."<<endl;
number = 110;
// to see if 110 can be splitted into 7 integer's cube
result = Split<7,3>()(number);
if(result.size() >0)
{
cout<<number<<" can be splitted as: "<<endl;
for(int i=0; i<result.size(); ++i)
{
vector<int> temp = result[i];
for(int j=0; j<temp.size(); ++j)
cout<<temp[j]<<',';
cout<<endl;
}
cout<<endl;
}
else
cout<<"No solution for "<<number<<"."<<endl;
number = 17;
// if N=1, then this algorithm degraded into a simple program to devide M into N parts
// and, this is the template's default mode .
result = Split<5>()(number);
if(result.size() >0)
{
cout<<number<<" can be splitted as: "<<endl;;
for(int i=0; i<result.size(); ++i)
{
vector<int> temp = result[i];
for(int j=0; j<temp.size(); ++j)
cout<<temp[j]<<',';
cout<<endl;
}
}
else
cout<<"No solution for "<<number<<"."<<endl;
return 0;
}