要求:
一个正整数n可以写为几个正整数的和,如:
4=4
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1
输入一个正整数,找出符合这种要求的所有正整数序列(序列不重复)
算法思想:
以n=6为例,将数继序列暂时存于a[MAXCOL]中,且初始时值全为1。
对数组中从jcol列开始的newn个元素进行操作f(6,0,0) ——函数GetCombinations(newn,newj,col)
col记录调用该函数时是在第col列。
初始化
count=6
j=0,newn=0
count=n
1. 如果count>1,令a[jcol]=count;
若count>a[col],表明该尝试不满足条件,count=count-1,重复1;
否则将该行第jcol+1列到jcol+count-1列的值改为0;
否则,退出;
2. newn=n-count
3. 如果new>1,则对从该行开始从jcol+count开始的newn个元素进行类似操作,并返回该新的newn对应的序列个数;
否则,count=count-1,返回1。
算法比较:
“acm题目及我的程序(3)——正整数n的加法组合”——使用二维数组存放加法序列
#define MAXROW 12000
#define MAXCOL 20
a[MAXROW][MAXCOL]
算法效率低,空间浪费严重
“acm题目及我的程序(3)——正整数n的加法组合(改进)”——使用二维数组存放加法序列
a[MAXROW][MAXCOL]
#define MAXROW 6000
#define MAXCOL 30
算法效率高,空间浪费不严重
“acm题目及我的程序(3)——正整数n的加法组合(改进2)”——使用动态二维数组存放加法序列
vector<vector<int> > m_venline
算法效率高,空间浪费很少
本文算法——使用一维数组存放加法序列,且计算每个n的加法序列的个数
a[MAXCOL]
算法效率最高,空间根本不浪费
代码如下:
/**/
/************************************************************************
* 一个正整数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
<
CONIO.H
>
#include
<
vector
>
using
namespace
std;
#define
MAXCOL 80
#define
FILENAMELENGTH 100
class
AdditionCombination
...
{
public:
int a[MAXCOL];
int m_number; //条用GetCombinations函数时count的值
public:
AdditionCombination(int number)
...{
m_number=number;
for(int j=0;j<MAXCOL;j++)
a[j]=1;
}
~AdditionCombination()...{}
void Initialize()
...{
for(int j=0;j<m_number;j++)
a[j]=1;
}
void Initialize(int jcol)
...{
for(int j=jcol;j<m_number;j++)
a[j]=1;
}
int GetCombinations(int n,int jcol,int col);
void display(int n);
}
;
//
在数组中从irow行,jcol列开始对n阶子矩阵进行
//
col记录调用该函数前jcol的值
int
AdditionCombination::GetCombinations(
int
n,
int
jcol,
int
col)
...
{
int nTotalCount=0;
int j=0,newn=0;
int count=n;
while(count>1)
...{
if(jcol==0)
Initialize();
else
Initialize(jcol);
a[jcol]=count;
//算法优化,删除不满足的序列
if(a[jcol]>a[col])
...{
count--;
continue;
}
for(j=jcol+1;j<jcol+count;j++)
a[j]=0;
newn=n-count;
if(newn>1)
...{
int newj=jcol+count;
int newcount=GetCombinations(newn,newj,jcol);
nTotalCount+=newcount;
}
count--;
//display(m_number);
nTotalCount++;
}
if(jcol==0)
...{
Initialize();
//display(m_number);
nTotalCount++;
}
else
Initialize(jcol);
return nTotalCount;
}
void
AdditionCombination::display(
int
n)
...
{
printf(" %d=%d",n,a[0]);
for(int j=1;j<n;j++)
...{
if(a[j])
printf("+%d",a[j]);
}
}
//
将结果写入文件
void
WriteToFile(vector
<
vector
<
int
>
>
info)
...
{
char filename[FILENAMELENGTH];
int size=info.size();
//构造文件名
sprintf(filename,"%d-%d result.txt",info[0][0],info[size-1][0]);
FILE *fp=fopen(filename,"w");
if(fp==NULL)
...{
printf("can not wirte file!");
exit(0);
}
//写入个数
for(int i=0;i<size;i++)
fprintf(fp,"n=%d count=%d ",info[i][0],info[i][1]);
fclose(fp);
}
//
显示菜单
void
show_menu()
...
{
printf("--------------------------------------------- ");
printf("input command to test the program ");
printf(" i or I : input n to test ");
printf(" t or T : get count from n1 to n2 ");
printf(" q or Q : quit ");
printf("--------------------------------------------- ");
printf("$ input command >");
}
void
main()
...
{
char sinput[10];
int n;
show_menu();
scanf("%s",sinput);
while(stricmp(sinput,"q")!=0)
...{
if(stricmp(sinput,"i")==0)
...{
printf(" please input an integer:");
scanf("%d",&n);
AdditionCombination obj(n);
int count=obj.GetCombinations(n,0,0);
printf(" count = %d ",count);
}
else if(stricmp(sinput,"t")==0)
...{
int n1,n2;
printf(" please input the begin number:");
scanf("%d",&n1);
printf(" please input the end number:");
scanf("%d",&n2);
printf(" press any key to start ... ");
getch();
vector<vector<int> > info;
vector<int> line;
AdditionCombination obj(n1);
for(int i=n1;i<=n2;i++)
...{
obj.Initialize();
obj.m_number=i;
int count=obj.GetCombinations(i,0,0);
printf(" n=%d count=%d ",i,count);
line.clear();
line.push_back(i);
line.push_back(count);
info.push_back(line);
}
printf(" ");
//写入文件
printf("$ write the numbers to file(Y,N)? >");
scanf("%s",sinput);
if(stricmp(sinput,"y")==0) //写入文件
...{
WriteToFile(info);
printf(" write successfully! ");
}
printf(" ");
}
//输入命令
printf("$ input command >");
scanf("%s",sinput);
}
}
运行结果如下:
输入从n1=30到n2=40的测试结果:
n1=1,n2=80的结果如下(文件1-80 result.txt):
n=1 count=1
n=2 count=2
n=3 count=3
n=4 count=5
n=5 count=7
n=6 count=11
n=7 count=15
n=8 count=22
n=9 count=30
n=10 count=42
n=11 count=56
n=12 count=77
n=13 count=101
n=14 count=135
n=15 count=176
n=16 count=231
n=17 count=297
n=18 count=385
n=19 count=490
n=20 count=627
n=21 count=792
n=22 count=1002
n=23 count=1255
n=24 count=1575
n=25 count=1958
n=26 count=2436
n=27 count=3010
n=28 count=3718
n=29 count=4565
n=30 count=5604
n=31 count=6842
n=32 count=8349
n=33 count=10143
n=34 count=12310
n=35 count=14883
n=36 count=17977
n=37 count=21637
n=38 count=26015
n=39 count=31185
n=40 count=37338
n=41 count=44583
n=42 count=53174
n=43 count=63261
n=44 count=75175
n=45 count=89134
n=46 count=105558
n=47 count=124754
n=48 count=147273
n=49 count=173525
n=50 count=204226
n=51 count=239943
n=52 count=281589
n=53 count=329931
n=54 count=386155
n=55 count=451276
n=56 count=526823
n=57 count=614154
n=58 count=715220
n=59 count=831820
n=60 count=966467
n=61 count=1121505
n=62 count=1300156
n=63 count=1505499
n=64 count=1741630
n=65 count=2012558
n=66 count=2323520
n=67 count=2679689
n=68 count=3087735
n=69 count=3554345
n=70 count=4087968
n=71 count=4697205
n=72 count=5392783
n=73 count=6185689
n=74 count=7089500
n=75 count=8118264
n=76 count=9289091
n=77 count=10619863
n=78 count=12132164
n=79 count=13848650
n=80 count=15796476