POJ 1032 / Northeastern Europe 1998 Parliament (贪心)

http://poj.org/problem?id=1032


题意:把N个人分成若干组且每组人数不同,每天每组派一个人出来开会,并且每天开会的这群人不与前面的日子的开会人群不完全相同。

也就是说,求N1+N2+...+Nn=N,使N1,N2,...,Nn都不相等且他们的乘积最大。


思路:分的组越多乘积越大(在题意下ab>a+b)


则有分法:设有一连续递增序列为2,3,...,i,和sum<=n,则: 
1.若剩余值(n-sum)等于i,则最后输出序列为:3,4,...,i,i+2,即将原最大序列每项加1,再将最后剩余的一个1加到最后一项上。 
2.若剩余值(n-sum)小于i,则从序列的最大项i开始,从大到小依次将每项加1,直到剩余值用完。 


分法合理性的证明:

首先说说连续,可以看到最后结果a[i]-a[i-1]<=2,也就是相邻两个数不能相差2以上,因为如果a[i]-a[i-1]=3,那么显然a[i-1]+1,a[i]-1也是满足要求的,且它们之间的乘积大于原来的,因此当相邻两个数相差>2时,总可以找到它们之间的两个数使得结果是更优的。

再来说说该序列必须以2或3开始,若序列第一项为5,则5=2+3,而2*3>5使得结果更优,对于大于5的第一项有类似结果。
再考虑4为第一项,根据前面的第一条,那么第二项只能为5或6.对于4,5可以分解为2,3,4使得结果更优。而对于4,6可以分解为2,3,5使得结果更优。因此可以看到该序列不可能是以大于3为开始的。


完整代码:

/*0ms,356KB*/

#include<cstdio>

int main()
{
	int n;
	scanf("%d", &n);
	int i = 2, sum = 0;
	while (sum + i <= n)
	{
		sum += i;
		++i;
	}
	int diff = n - sum, j;
	if (diff == i - 1)
	{
		for (j = 3; j < i; ++j)
			printf("%d ", j);
		printf("%d", j + 1);
	}
	else
	{
		for (j = 2; j < i - diff; ++j)
			printf("%d ", j);
		for (; j < i; ++j)
			printf("%d ", j + 1);//最后多一个空格不要紧
	}
	putchar(10);
	return 0;
}

你可能感兴趣的:(C++,ACM,poj,贪心)