poj 1032 Parliament 整数拆分

题意:简单说,就是给你一个数n(5=<N<=1000),然后把这个数拆分成许多不同的自然数,使得这些自然数的乘积最大。

解题:无意中在一个奥数网站上看到整数拆分这个知识,觉得不错就搜了一个水题试试,结果果然很神奇;

根据均值不等式得,可知最好拆分后的数相差不要太大。可以从自然数2加起,用sum(n)表示和,sum(2)=2,使其满足sum(n-1)<N;sum(n)>=N;

则sum(n)-N的差值只可能是0,1,……n-1。

1、当差值是0,就讲a拆分成2,3,……n-1,n;

2、当差值是1,就将2去了,加到最后的n上即:3,4,……n-1,n+1;

3、当差值大于1,就在拆分的结果中找到和差值相等的那个数,把它去掉就好了。

详细的请到那个奥数网页http://www.aoshu.com/e/20090920/4b8bd0191bae7.shtml上查看,但是提醒读者,他这个网页上讲的有点错误,就是当差值为1的时候,下面已有本人的留言给予纠正。

同时在其他博客上也看了一点证明(以下摘抄自它人博客http://blog.himdd.com/?p=1918):

假设最大积的分解为:
N=a1+a2+a3+…+a[t-2]+a[t-1]+a[t] (t是分解的数目,a1<a2<a3<...<a[t-2]<a[t-1]<a[t])
 下面是该数列的性质及其证明:
1)a1>1;
如果a1=1,则a1和a[t]可以由a[t]+a1=a[t]+1来替代,从而得到更大的积;

2)对于所有的i,有a[i+1]-a[i]<= 2;
如果存在i使得a[i+1]-a[i]>=3,则a[i]和a[i+1]可以替换为a[i]+1,a[i+1]-1,从而使乘积更大;

3)最多只存在一个i使得a[i+1]-a[i]=2;
如果i< j且a[i+1]-a[i]=2、a[j+1]-a[j]=2,则a[i],a[j+1]可以替换为a[i]+1,a[j+1]-1,从而使得乘积更大;

4)a1<=3;
如果a1>=4,则a1和a2可以替换为2,a1-1,a2-1,从而使得乘积更大;

5)如果a1=3且存在i满足a[i+1]-a[i]=2,则i一定等于t-1;
如果i<t-1,则a[i+2]可以替换为2,a[i+2]-2,从而使得乘积更大;< p="">

将上面5条性质综合一下,得到该数列满足:
1)1< a1< 4
2)a[i+1]-a[i] <=2(该序列按升序排序)
3)a[i+1]-a[i]=2的情况最多只有一个

因此,我们得到最大的乘积的做法就是求出从2开始的最大连续(由上面总结的性质2和3可知)自然数列之和A,使得A的值不超过N,具体分析如下:
对输入的N,找到k满足:
A=2+3+4+...+(k-1)+k <= N < A+(k+1) = B
假设N=A+p(0<=p< k+1),即A+p是最大积的数列
1)p=0,则最大积是A;
2)1<=p<=k-1,则最大积是B-{k+1-p},即从数列的最大项i开始,从大到小依次每项加1,知道p=0为止;
3)p=k,则最大积是A+p=A+k=A-{2}+{k+2};( =3+4+...+k+( k+2) )。



本人代码如下:

#include <stdio.h>
int main()
{
	int n,shu[1000];
	while(~scanf("%d",&n))
	{
		int sum=0,i,j;
		for(i=2;sum+i<n;i++)
		{
			shu[i-1]=i;
			sum+=i;
		}
		sum+=i;
		shu[i-1]=i;
		shu[0]=i-1;
		if(sum==n)
		{
			for(i=1;i<=shu[0];i++)
				printf("%d ",shu[i]);
			printf("\n");
		}
		if(sum-n==1)
		{
			for(i=2;i<shu[0];i++)
				printf("%d ",shu[i]);
			printf("%d ",shu[i]+1);
			printf("\n");
		}
		if(sum-n>=2)
		{
			for(i=1;i<=shu[0];i++)
			{
				if(sum-n!=shu[i])
				printf("%d ",shu[i]);
			}
			printf("\n");
		}
	}
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值