ACWING25. 剪绳子(剑指offer,数学/dp)

2024-04-16 01:32
文章标签 dp 数学 offer 绳子 acwing25

本文主要是介绍ACWING25. 剪绳子(剑指offer,数学/dp),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

给你一根长度为 n 绳子,请把绳子剪成 m 段(m、n 都是整数,2≤n≤58 并且 m≥2)。

每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]k[1] … k[m] 可能的最大乘积是多少?

例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到最大的乘积18。

样例
输入:8

输出:18

思路:

  1. 直观的思路是在确定分了多少段的前提下,分的越平均越好。这不难理解,假设分平均以后是a,a,那么打破平均变成a+1,a-1,乘积变成了a2- 1,反而变小了
class Solution {
public:int maxProductAfterCutting(int length) {int ans = 0;for(int i = 2;i <= length;i++) {int num = 1;int a = length / i;int b = length % i;for(int j = 1;j <= b;j++) num *= a + 1;for(int j = 1;j <= i - b;j++) num *= a;ans = max(ans,num);}return ans;}
};
  1. 还可以利用动态规划,定义dp[i]代表长度为i的时候分出来的最大成绩。可以得到
    d p [ i ] = m a x ( d p [ i ] , d p [ i − j ] ∗ j ) dp[i] = max(dp[i],dp[i - j] * j) dp[i]=max(dp[i],dp[ij]j)
    但是注意每一个绳子至少分两段,这意味着dp[i - j]至少分了两段,但或许 i - j 这个长度的绳子不分反而更优。所以
    d p [ i ] = m a x ( ( i − j ) ∗ j , d p [ i − j ] ∗ j , d p [ i ] ) dp[i] = max((i - j) * j,dp[i - j]*j,dp[i]) dp[i]=max((ij)j,dp[ij]j,dp[i])
class Solution {
public:int dp[105];int maxProductAfterCutting(int length) {memset(dp,0,sizeof(dp));dp[1] = 1;for(int i = 2;i <= length;i++) {for(int j = 1;j < i;j++) dp[i] = max((i - j) * j,max(dp[i],dp[i - j] * j));}return dp[length];}
};

上述两种方法都包含了两个循环,是n方级别的算法。是否存在更高效的算法呢?这就是接下来介绍的数学方法。

一个已知的结论是:所有大于3的数,都可以由2和3组成,如4 = 2 + 2,5 = 2 + 3,那么答案与2和3有关呢?

假设对于 n ≥ 4 n ≥ 4 n4
n = 4 n = 4 n=4时,枚举得到 n = 2 + 2 n = 2+2 n=2+2时,结果最优,为4.
n > 4 n > 4 n>4
将n拆出一个2得到 n = n − 2 + 2 n = n-2+2 n=n2+2,
那么 2 ∗ ( n − 2 ) = 2 n − 4 = n + ( n − 4 ) > n 2 * (n-2)=2n-4=n+(n-4)>n 2(n2)=2n4=n+(n4)>n
对于3同理: 3 ∗ ( n − 3 ) = n + 2 n − 9 > n 3*(n-3)=n+2n-9>n 3(n3)=n+2n9>n

而假设将n拆出一个数k
k > 3 k>3 k>3
那么乘积为 k ∗ ( n − k ) k*(n-k) k(nk)

我们知道,k可以拆成2和3的倍数和,而没拆一次,都会使得新产生两个数的乘积大于k。

所以可以将k拆成 k = k − 3 + 3 , k = k − 2 + 2 。 k = k - 3 + 3,k = k - 2 + 2。 k=k3+3,k=k2+2
结果为 ( k − 3 ) ∗ 3 ∗ ( n − k ) (k-3)*3*(n-k) (k3)3(nk)
或者 ( k − 2 ) ∗ 2 ( n − k ) (k-2)*2(n-k) (k2)2(nk)
对于 k − 3 , k − 2 k-3,k-2 k3,k2以及 n − k n-k nk,因为也能拆成2和3,所以也能应用同样的结论:n拆成2和3,乘积最大。

但是注意到当 3 ∗ 3 > 2 ∗ 2 ∗ 2 3 * 3 > 2 * 2 * 2 33>222,当n≥6的时候,尽量拆出3最优。

综合以上,
如果n%2 = 1,先将4提取出来(4要拆成2),res = 4
如果n%2 = 2,先提取一个2出来(这个2拆不了),res = 2。
剩下的部分全部拆成3,复杂度为O(n)。

如果再利用快速幂,复杂度可以进一步优化为O(logn)

class Solution {
public:int qpow(int n,int m) {int res = 1;while(m) {if(m & 1) res = res * n;n = n * n;m >>= 1;}return res;}int maxProductAfterCutting(int n) {if(n <= 3) return (n - 1);int res = 1;if(n % 3 == 1) n -= 4,res = 4;else if(n % 3 == 2)  n -= 2,res = 2;res *= qpow(3,n / 3);return res;}
};

这篇关于ACWING25. 剪绳子(剑指offer,数学/dp)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/907463

相关文章

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10014 Simple calculations(数学推导)

直接按照题意来推导最后的结果就行了。 开始的时候只做到了第一个推导,第二次没有继续下去。 代码: #include<stdio.h>int main(){int T, n, i;double a, aa, sum, temp, ans;scanf("%d", &T);while(T--){scanf("%d", &n);scanf("%lf", &first);scanf

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=

uva 11044 Searching for Nessy(小学数学)

题意是给出一个n*m的格子,求出里面有多少个不重合的九宫格。 (rows / 3) * (columns / 3) K.o 代码: #include <stdio.h>int main(){int ncase;scanf("%d", &ncase);while (ncase--){int rows, columns;scanf("%d%d", &rows, &col

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]