剪绳子

题目:
给你一根长度为n绳子,请把绳子剪成m段(m、n都是整数,n>1并且m≥1)。
每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]k[1]…*k[m]可能的最大乘
积是多少?例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,
此时得到最大的乘积18。

思路:
动态规划:
把最优解储存在一个product数组里,设f(n)为长度为n的绳子的最大乘积(n>=2),则有
f(2)=1,f(3)=2,f(n)=max(f(i)*f(n-i)),其中i和n-i是将绳子分为长度为i和n-i的两段,i是需要遍历的量,从1到n/2

int maxProductAfterCutting_solution1(int length)//动态规划
{
	if (length <= 1)
		return 0;
	if (length == 2 || length == 3)
		return length - 1;

	int *product = new int[length + 1];
	product[0] = 0;
	product[1] = 1;//设置为1,避免相乘为0,长度为1的时候实际上乘积为0;
	product[2] = 2;//product[2]表示长度为2的子绳子,product[3]同理
	product[3] = 3;//从product[4]开始,product[i]的含义成了长度为i的绳子的最优解
	int max;
	for (int i = 4; i < length + 1; ++i)
	{
		max = INT_MIN;
		for (int j = 1; j <= i / 2; ++j)
		{
			int temp = product[j] * product[i - j];
			if (max < temp)
				max = temp;
			product[i] = max;
		}
	}
	max = product[length];
	delete[] product;
	return max;
}

动态规划的时间复杂度为O(n*n),空间复杂度为O(n)
下面介绍一下此题的贪婪算法,时间复杂度和空间复杂度都是O(1)
思路2:
采用贪婪算法,首先要知道指数函数的增长速度是最快的,所以当n>=5开始,我们把长度为n的绳子全部拆成长度为3或2的小绳子,这样乘积是3的幂,自然要比长度不等的小绳子的乘积大,注意一下优先划分为3的幂,最后若剩下长度为4的绳子再划分为2的幂

int maxProductAfterCutting_solution2(int length)//贪婪算法
{
	if (length <= 1)
		return 0;
	if (length == 2 || length == 3)
		return length - 1;

	int timesOf3 = length / 3;
	if (length - timesOf3 * 3 == 1)//如果最后一段长度是4的话,我们不应把他剪成1和3,应该剪成2和2,因为1*3<2*2
	{
		timesOf3--;
	}
	int timesOf2 = (length - 3 * timesOf3) / 2;
	return (int)(pow(3, timesOf3))*(int)(pow(2, timesOf2));
}

完整代码包含测试代码:

#include <iostream>

using namespace std;

int maxProductAfterCutting_solution1(int length)//动态规划
{
	if (length <= 1)
		return 0;
	if (length == 2 || length == 3)
		return length - 1;

	int *product = new int[length + 1];
	product[0] = 0;
	product[1] = 1;//设置为1,避免相乘为0,长度为1的时候实际上乘积为0;
	product[2] = 2;//product[2]表示长度为2的子绳子,product[3]同理
	product[3] = 3;//从product[4]开始,product[i]的含义成了长度为i的绳子的最优解
	int max;
	for (int i = 4; i < length + 1; ++i)
	{
		max = INT_MIN;
		for (int j = 1; j <= i / 2; ++j)
		{
			int temp = product[j] * product[i - j];
			if (max < temp)
				max = temp;
			product[i] = max;
		}
	}
	max = product[length];
	delete[] product;
	return max;
}

int maxProductAfterCutting_solution2(int length)//贪婪算法
{
	if (length <= 1)
		return 0;
	if (length == 2 || length == 3)
		return length - 1;

	int timesOf3 = length / 3;
	if (length - timesOf3 * 3 == 1)//如果最后一段长度是4的话,我们不应把他剪成1和3,应该剪成2和2,因为1*3<2*2
	{
		timesOf3--;
	}
	int timesOf2 = (length - 3 * timesOf3) / 2;
	return (int)(pow(3, timesOf3))*(int)(pow(2, timesOf2));
}

// ====================测试代码====================
void test(const char* testName, int length, int expected)
{
	int result1 = maxProductAfterCutting_solution1(length);
	if (result1 == expected)
		std::cout << "Solution1 for " << testName << " passed." << std::endl;
	else
		std::cout << "Solution1 for " << testName << " FAILED." << std::endl;

	int result2 = maxProductAfterCutting_solution2(length);
	if (result2 == expected)
		std::cout << "Solution2 for " << testName << " passed." << std::endl;
	else
		std::cout << "Solution2 for " << testName << " FAILED." << std::endl;
}

void test1()
{
	int length = 1;
	int expected = 0;
	test("test1", length, expected);
}

void test2()
{
	int length = 2;
	int expected = 1;
	test("test2", length, expected);
}

void test3()
{
	int length = 3;
	int expected = 2;
	test("test3", length, expected);
}

void test4()
{
	int length = 4;
	int expected = 4;
	test("test4", length, expected);
}

void test5()
{
	int length = 5;
	int expected = 6;
	test("test5", length, expected);
}

void test6()
{
	int length = 6;
	int expected = 9;
	test("test6", length, expected);
}

void test7()
{
	int length = 7;
	int expected = 12;
	test("test7", length, expected);
}

void test8()
{
	int length = 8;
	int expected = 18;
	test("test8", length, expected);
}

void test9()
{
	int length = 9;
	int expected = 27;
	test("test9", length, expected);
}

void test10()
{
	int length = 10;
	int expected = 36;
	test("test10", length, expected);
}

void test11()
{
	int length = 50;
	int expected = 86093442;
	test("test11", length, expected);
}

int main(int agrc, char* argv[])
{
	test1();
	test2();
	test3();
	test4();
	test5();
	test6();
	test7();
	test8();
	test9();
	test10();
	test11();

	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值