要求:
一个正整数n可以写为几个正整数的和,如:
4=4
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1
输入一个正整数,找出符合这种要求的所有正整数序列(序列不重复)
算法思想:
在“acm题目及我的程序(3)——正整数n的加法组合”中,我们使用二维数组存放加法序列,实现规定MAXROW和MAXCOL,这样的数组在程序运行时分配的内存在栈区,其大小受限制,程序定义的MAXROW和MAXCOl如下:
#define MAXROW 12000
#define MAXCOL 20
#define MAXCOL 20
所以运行时,n最大不能超过20,且n=20时,其求解出的所有序列为10946个,但满足条件的序列仅有627个,故时间和空间浪费都很严重。
而在“acm题目及我的程序(3)——正整数n的加法组合(改进)”中,虽然空间的严重浪费解决的很好,但还是有部分空间浪费,程序定义的MAXROW和MAXCOl如下:
#define MAXROW 6000
#define MAXCOL 30
#define MAXCOL 30
所以在n很小时,例如n=12时,求出满足条件的序列有77个,空间浪费也很严重,而n最大为30时,求出的序列为5604个,也有浪费。
故在此文中,将存储空间改为动态二维数组,采用vector实现,且在求解的过程中,直接判断,如果序列中的某个数据大于前面的数据,则直接进行下一次计算,即节省空间,又提高了效率。但因vector为数据容器,对其操作都是采用其标准函数,而不像数组直接对内存读写,效率会稍微有些降低。
以n=6为例,将数继序列存于vector<vector<int> > m_vecline中,且初始时m_vecline为空,只是在需要的时候才向该数组增加一行。
对数组中从irow行,jcol列开始的newn阶子矩阵进行操作f(6,0,0,0) ——函数GetCombinations(newn,newi,newj,col)
col记录调用该函数时是在第col列。
初始化
count=6
j=0,newn=0;
i=0
i=0
count=n
1. 如果count>6,令m_vecline[i][jcol]=count;
若count>m_vecline[i][col],表明该尝试不满足条件,count=count-1,重复1;
否则将该行第jcol+1列到jcol+count-1列的值改为0;
否则,退出;
2. newn=n-count
3. 如果new>1,则对从该行开始从jcol+count开始的newn阶子矩阵进行类似操作,并返回增加的行数,并将该行的前jcol个元素复制到新增加的每一行;
否则,count=count-1,处理下一行
代码如下:提供将结果写入文件的功能
/**//************************************************************************
* 一个正整数n可以写为几个正整数的和
* 4=4
* 4=3+1
* 4=2+2
* 4=2+1+1
* 4=1+1+1+1
* 要求:输入一个正整数,找出符合这种要求的所有正整数序列(序列不重复)
************************************************************************/
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define FILENAMELENGTH 100 //文件名长度
class AdditionCombination
...{
public:
vector<vector<int> > m_vecline;
int m_number;
public:
AdditionCombination(int n)...{m_number=n;m_vecline.clear();}
~AdditionCombination()...{}
void AddANewLine(int row);
int GetCombinations(int n,int irow,int jcol,int col);
void display(int n,int count);
void WriteToFile(int n,int count);
};
//add a new line including n valus 1
void AdditionCombination::AddANewLine(int row)
...{
if(row>=m_vecline.size())
...{
vector<int> line;
for(int i=0;i<m_number;i++)
line.push_back(1);
m_vecline.push_back(line);
}
}
//在数组中从irow行,jcol列开始对n阶子矩阵进行
//col记录调用该函数前jcol的值
int AdditionCombination::GetCombinations(int n,int irow,int jcol,int col)
...{
if(n==2)
...{
AddANewLine(irow);
m_vecline[irow][jcol]=2;
m_vecline[irow][jcol+1]=0;
return 2;
}
int j=0,newn=0;
int i=irow; //from line irow
int count=n; //count is the number of 1 to be added
while(count>1)
...{
AddANewLine(i);
m_vecline[i][jcol]=count;
//算法优化,删除不满足的序列
int comi=0;
if(m_vecline[i][col]==1)
comi=irow;
else
comi=i;
if(m_vecline[i][jcol]>m_vecline[comi][col]) //unvalid line
...{
count--;
continue;
}
for(j=jcol+1;j<jcol+count;j++)
m_vecline[i][j]=0;
newn=n-count;
if(newn>1)
...{
int newi=i;
int newj=jcol+count;
int newcount=GetCombinations(newn,newi,newj,jcol);
//copy the front count elements of the ith line for newn-1 times
AddANewLine(i+newcount);
for(int k=1;k<newcount;k++)
...{
for(int t=jcol;t<newj;t++)
m_vecline[newi+k][t]=m_vecline[newi][t];
}
i+=newcount;
count--;
}
else
...{
i++;
count--;
}
}
return i-irow+1;
}
void AdditionCombination::display(int n,int count)
...{
for(int i=0;i<count;i++)
...{
printf(" %d=%d",n,m_vecline[i][0]);
for(int j=1;j<n;j++)
...{
if(m_vecline[i][j])
printf("+%d",m_vecline[i][j]);
}
}
printf(" count=%d vector size=%d ",count,m_vecline.size());
}
//将结果写入文件
void AdditionCombination::WriteToFile(int n,int count)
...{
char filename[FILENAMELENGTH];
//构造文件名
sprintf(filename,"%d - result.txt",n);
FILE *fp=fopen(filename,"w");
if(fp==NULL)
...{
printf("can not wirte file!");
exit(0);
}
//写入个数
fprintf(fp,"total number = %d ",count);
for(int i=0;i<count;i++)
...{
fprintf(fp," %d=%d",n,m_vecline[i][0]);
for(int j=1;j<n;j++)
...{
if(m_vecline[i][j])
fprintf(fp,"+%d",m_vecline[i][j]);
}
}
fclose(fp);
}
//显示菜单
void show_menu()
...{
printf("--------------------------------------------- ");
printf("input command to test the program ");
printf(" i or I : input n to test ");
printf(" q or Q : quit ");
printf("--------------------------------------------- ");
printf("$ input command >");
}
void main()
...{
char
* 一个正整数n可以写为几个正整数的和
* 4=4
* 4=3+1
* 4=2+2
* 4=2+1+1
* 4=1+1+1+1
* 要求:输入一个正整数,找出符合这种要求的所有正整数序列(序列不重复)
************************************************************************/
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define FILENAMELENGTH 100 //文件名长度
class AdditionCombination
...{
public:
vector<vector<int> > m_vecline;
int m_number;
public:
AdditionCombination(int n)...{m_number=n;m_vecline.clear();}
~AdditionCombination()...{}
void AddANewLine(int row);
int GetCombinations(int n,int irow,int jcol,int col);
void display(int n,int count);
void WriteToFile(int n,int count);
};
//add a new line including n valus 1
void AdditionCombination::AddANewLine(int row)
...{
if(row>=m_vecline.size())
...{
vector<int> line;
for(int i=0;i<m_number;i++)
line.push_back(1);
m_vecline.push_back(line);
}
}
//在数组中从irow行,jcol列开始对n阶子矩阵进行
//col记录调用该函数前jcol的值
int AdditionCombination::GetCombinations(int n,int irow,int jcol,int col)
...{
if(n==2)
...{
AddANewLine(irow);
m_vecline[irow][jcol]=2;
m_vecline[irow][jcol+1]=0;
return 2;
}
int j=0,newn=0;
int i=irow; //from line irow
int count=n; //count is the number of 1 to be added
while(count>1)
...{
AddANewLine(i);
m_vecline[i][jcol]=count;
//算法优化,删除不满足的序列
int comi=0;
if(m_vecline[i][col]==1)
comi=irow;
else
comi=i;
if(m_vecline[i][jcol]>m_vecline[comi][col]) //unvalid line
...{
count--;
continue;
}
for(j=jcol+1;j<jcol+count;j++)
m_vecline[i][j]=0;
newn=n-count;
if(newn>1)
...{
int newi=i;
int newj=jcol+count;
int newcount=GetCombinations(newn,newi,newj,jcol);
//copy the front count elements of the ith line for newn-1 times
AddANewLine(i+newcount);
for(int k=1;k<newcount;k++)
...{
for(int t=jcol;t<newj;t++)
m_vecline[newi+k][t]=m_vecline[newi][t];
}
i+=newcount;
count--;
}
else
...{
i++;
count--;
}
}
return i-irow+1;
}
void AdditionCombination::display(int n,int count)
...{
for(int i=0;i<count;i++)
...{
printf(" %d=%d",n,m_vecline[i][0]);
for(int j=1;j<n;j++)
...{
if(m_vecline[i][j])
printf("+%d",m_vecline[i][j]);
}
}
printf(" count=%d vector size=%d ",count,m_vecline.size());
}
//将结果写入文件
void AdditionCombination::WriteToFile(int n,int count)
...{
char filename[FILENAMELENGTH];
//构造文件名
sprintf(filename,"%d - result.txt",n);
FILE *fp=fopen(filename,"w");
if(fp==NULL)
...{
printf("can not wirte file!");
exit(0);
}
//写入个数
fprintf(fp,"total number = %d ",count);
for(int i=0;i<count;i++)
...{
fprintf(fp," %d=%d",n,m_vecline[i][0]);
for(int j=1;j<n;j++)
...{
if(m_vecline[i][j])
fprintf(fp,"+%d",m_vecline[i][j]);
}
}
fclose(fp);
}
//显示菜单
void show_menu()
...{
printf("--------------------------------------------- ");
printf("input command to test the program ");
printf(" i or I : input n to test ");
printf(" q or Q : quit ");
printf("--------------------------------------------- ");
printf("$ input command >");
}
void main()
...{
char