正整数拆分算法

Jupin 2006-03-01 01:35:53
题目:N = n1+n2+...+nk (k > 1, n1,..,nk > 0)
其中,N是待拆分的正整数。

例子:2 = 1+1
3 = 1+2 = 1+1+1 = 2+1

最简单的是用递归实现,我是这么写的:
int aaa(int n, char *s)
{
char o[1280];
int i;

if (1 == n)
{
return 0;
}

for (i = 1; i < n; i++)
{
printf("%s+%d+%d\n", s, i, n-i);

sprintf(o, "%s+%d", s, i);
kkk(n-i, o);
}

return 0;
}
但是显然,当N取较大值时,这个程序会崩溃掉。
几经思考,我写一个非递归版本。但很想看看大家的奇思妙想,
所以先不贴我的,以免误导大家。

不一定要具体编码,说说想法也行。万分感谢。
...全文
1118 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
Jupin 2006-03-06
  • 打赏
  • 举报
回复
看来还得靠自己多想想
xjq2003 2006-03-06
  • 打赏
  • 举报
回复
简单的方法也是好方法
wjd7623054 2006-03-06
  • 打赏
  • 举报
回复
mark
Jupin 2006-03-02
  • 打赏
  • 举报
回复
to 回复人:xiaocai0001(高楼目尽欲黄昏/梧桐叶上萧萧雨) ( 两星(中级)) 信誉:97 2006-03-02
我有测试过,没有问题呀,就是n不能太大。

to 复人:popy007(Twinsen) ( 四级(中级)) 信誉:100 2006-03-02 12:47:00
谢谢指教。只是全排列算法也是递归吧?
popy007 2006-03-02
  • 打赏
  • 举报
回复
n1 ~ nN中的N就是i
popy007 2006-03-02
  • 打赏
  • 举报
回复
int aaa(int n, char *s)
{
for(int i = 2; i <= n; ++i)
{
将n拆成i个数的和。将1到n-i的所有数字,
用排列的方式全部放到
n1 ~ nN这N的数字中,进行筛选:

如果 n1+n2+...+nN == n,记录当前的排列
否则 继续进行下一次排列

直到所有的排列全部经历一次
}
最后,记录下的所有排列就是拆分结果。
}
xiaocai0001 2006-03-02
  • 打赏
  • 举报
回复
递推呢?

感觉你的递归程序好像不太对
Jupin 2006-03-02
  • 打赏
  • 举报
回复
int aaa(int n, char *s)
{
char o[1280];
int i;

if (1 == n)
{
return 0;
}

for (i = 1; i < n; i++)
{
printf("%s+%d+%d\n", s, i, n-i);

sprintf(o, "%s+%d", s, i);
aaa(n-i, o);
}

return 0;
}

原帖有错,改正了。
算法版好像人不多呢,转到这试试:)
cunsh 2006-03-02
  • 打赏
  • 举报
回复
哦.不对.这个和你要的不一样.
cunsh 2006-03-02
  • 打赏
  • 举报
回复
如果有个子集的所有元素之和等于n. 那就是你要的了.
cunsh 2006-03-02
  • 打赏
  • 举报
回复
//这儿有个求1到n的所有子集的例子
//例如{1,2,3} 的子集有 {1} {2} {3} {1,2} {1,3} {2,3} {1,2,3}
#include<iostream>
#include<vector>
using namespace std;

vector<vector<int> > n;
void main()
{
int x;
cout<<"Input:";
cin >>x;

vector<int> m;
m.push_back(1);
n.push_back(m);
m.clear();

for (int i=2;i<=x;i++){

int k=n.size();

m.push_back(i);
n.push_back(m);
m.clear();

for (int j=0; j<k; j++){
m = n[j];
m.push_back(i);
n.push_back(m);
m.clear();
}
}
for (vector<vector<int> >::iterator l=n.begin();l!=n.end();l++)
{
for (vector<int>::iterator ll = (*l).begin(); ll != (*l).end(); ll++)
{
cout << *ll << " ";
}
cout << endl;
}
}
Jupin 2006-03-02
  • 打赏
  • 举报
回复
to: 回复人:cnheying(寒塘鹤影) ( 一级(初级)) 信誉:100 2006-03-02 15:14:00
我把分配到的数组做为栈了,其中p[0]放的是栈顶指针,p[1]...p[n]里放的是数据。
fdimim 2006-03-02
  • 打赏
  • 举报
回复
cnheying 2006-03-02
  • 打赏
  • 举报
回复
Jupin(T357)
我想到的另一个算法:
////////////////////////
能不能详细说明一下思想。看了半天没看懂。尤其是p[ p[] ].............
du51 2006-03-02
  • 打赏
  • 举报
回复
我想在考虑的问题是如何除去3+2=5和2+3=5这一类的重复分拆。
--------------------------
用贪婪算法.不会产生重复.
Jupin 2006-03-02
  • 打赏
  • 举报
回复
我想到的另一个算法:
int aaa(int n)
{
int *p;
int i;

p = (int *)malloc((n + 1) * sizeof(int));
if (NULL == p)
{
printf("memory alloc failed.\n");
return 1;
}

p[0] = 1;
p[1] = n;

while (1)
{
if (1 == p[p[0]])
{
if (p[0] < 3)
{
printf("%d = %d + %d\n", n, p[1], p[2]);
break;
}
else
{
p[p[0] - 2] += p[p[0]];
p[p[0]] = 0;
p[0]--;
}
}
else
{
p[p[0] + 1] = p[p[0]] - 1;
p[p[0]] = 1;
p[0]++;
}

printf("%d = %d", n, p[1]);
for (i = 2; i <= p[0]; i++)
{
printf(" + %d", p[i]);
}
printf("\n");
}

free(p);
return 0;
}
cnheying 2006-03-02
  • 打赏
  • 举报
回复
可以用高中的那个解方程思想:
1+1+ ....+1=n
从其中n-1个加号中选k个将1分为k+1组;每组中1的个数就是分拆后的因子。
如1+1+1+1=4选第1个 “+”的结果就是1+3=4;
至于组合怎么产生就不用我多说了。

我想在考虑的问题是如何除去3+2=5和2+3=5这一类的重复分拆。
popy007 2006-03-02
  • 打赏
  • 举报
回复
Jupin(T357)

全排列算法不需要递归。它只需要一次排序 + 遍历所有的排列。


比如对于一个int a[10] 一次排序:

sort(a); //

遍历所有的排序:

// java版本,只作为示意
boolean nextPermutation(int[] a)
{
int len = a.length;
int i=len-2;
for(; i>=0; --i)
if(a[i]<a[i+1]) break;
if(i<0) return false;

for(int j=len-1; j>=i; --j)
if(a[j]>a[i])
{
int t = a[i];
a[i] = a[j];
a[j] = t;
break;
}
for(int j=i+1; j<(len+i+1)/2; ++j)
{
int t = a[j];
a[j] = a[len+i-j];
a[len+i-j] = t;
}
return true;
}

while(nextPermutation(a)) [
doSomething();
}

就可以了。
逸学堂 2006-03-02
  • 打赏
  • 举报
回复
其中,N是待拆分的正整数
`~`~`~`~`~`~
解决这种问题的方法有很多中,比如贪吃算法,0-1算法都可以.
这类问题,是背包问题的一种变形.所以可以用背包思想去解决这类问题..

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧