在网上看到的acm题目,来源忘记了,现在贴出自己的算法。
要求:
一个正整数n可以写为几个正整数的和,如:
4=4
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1
输入一个正整数,找出符合这种要求的所有正整数序列(序列不重复)
算法思想:
以n=6为例,将数继序列存于a[MAXROW][6]中,且将数组a的所有值初始化为1
对数组中从irow行,jcol列开始的n阶子矩阵进行操作f(6,0,0)
初始化
count=6
j=0,newn=0;
i=0
i=0
count=n
1. 如果count>6,令a[i][jcol]=count,且将该行第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>
#define MAXROW 12000
#define MAXCOL 20
class AdditionCombination
...{
public:
int a[MAXROW][MAXCOL];
public:
AdditionCombination()...{}
~AdditionCombination()...{}
void Initialize(int n);
int GetCombinations(int n,int irow,int jcol);
int DeleteValidData(int n,int count,int& validcount);
void display(int n,int count,int validcount);
};
void AdditionCombination::Initialize(int n)
...{
for(int i=0;i<MAXROW;i++)
for(int j=0;j<MAXCOL;j++)
a[i][j]=1;
}
//在数组中从irow行,jcol列开始对n阶子矩阵进行
int AdditionCombination::GetCombinations(int n,int irow,int jcol)
...{
if(n==2)
...{
a[irow][jcol]=2;
a[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)
...{
a[i][jcol]=count;
for(j=jcol+1;j<jcol+count;j++)
a[i][j]=0;
newn=n-count;
if(newn>1)
...{
int newi=i;
int newj=jcol+count;
int newcount=GetCombinations(newn,newi,newj);
//copy the front count elements of the ith line for newn-1 times
for(int k=1;k<newcount;k++)
...{
for(int t=jcol;t<newj;t++)
a[newi+k][t]=a[newi][t];
}
i+=newcount;
count--;
}
else
...{
i++;
count--;
}
}
return i-irow+1;
}
//return the number of all addition sequence
int AdditionCombination::DeleteValidData(int n,int count,int& validcount)
...{
int t,j;
for(int i=1;i<count-1;i++)
...{
t=j=1;
while(j<n)
...{
while(a[i][j]==0)
j++;
if(j>=n)
break;
a[i][t++]=a[i][j];
a[i][j++]=0;
}
a[i][t]=0;
}
validcount=count;
for(i=1;i<count;i++)
...{
for(j=0;j<n-1;j++)
...{
if(a[i][j]>0 && a[i][j+1]>0)
...{
if(a[i][j]<a[i][j+1] )
...{
a[i][0]=0;
validcount--;
break;
}
}
}
}
return count;
}
void AdditionCombination::display(int n,int count,int validcount)
...{
for(int i=0;i<count;i++)
...{
if(a[i][0]==0)
continue;
printf(" %d=%d",n,a[i][0]);
for(int j=1;j<n;j++)
...{
if(a[i][j]==0)
break;
printf("+%d",a[i][j]);
}
}
printf(" count=%d sequences number=%d ",count,validcount);
}
//显示菜单
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 sinput[10];
int n;
show_menu();
scanf("%s",sinput);
while(stricmp(sinput,"q")!=0)
...{
if(stricmp(sinput,"i")==0)
...{
printf(" please input an integer (<21) :");
scanf("%d",&n);
AdditionCombination obj;
obj.Initialize(n);
int count=obj.GetCombinations(n,0,0);
int validcount=0;
obj.DeleteValidData(n,count,validcount);
obj.display(n,count,validcount);
}
//输入命令
printf("$ input command >");
scanf("%s",sinput);
}
}运行结果如下:
1. n=6
count=13表示所有序列个数为13,其中满足要求的序列个数为11
2. n=10
count=89表示所有序列为89个,满足要求的有42个
博客介绍了ACM题目的一个实例,要求找出正整数n的所有可能加法组合,不重复。例如,对于n=6,存在13种序列,其中11种符合要求。博主分享了实现这一算法的思想和运行结果。
11万+

被折叠的 条评论
为什么被折叠?



