题目:
给你一根长度为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;
}