CS-Notes/notes/14. 剪绳子.md

68 lines
2.2 KiB
Java
Raw Permalink Normal View History

2019-11-02 12:07:41 +08:00
# 14. 剪绳子
2020-11-05 02:09:40 +08:00
## 题目链接
2021-03-23 02:48:19 +08:00
[牛客网](https://www.nowcoder.com/practice/57d85990ba5b440ab888fc72b0751bf8?tpId=13&tqId=33257&tab=answerKey&from=cyc_github)
2019-11-02 12:07:41 +08:00
## 题目描述
把一根绳子剪成多段并且使得每段的长度乘积最大
```html
n = 2
return 1 (2 = 1 + 1)
n = 10
return 36 (10 = 3 + 3 + 4)
```
## 解题思路
### 贪心
2020-11-05 02:09:40 +08:00
尽可能得多剪长度为 3 的绳子并且不允许有长度为 1 的绳子出现如果出现了就从已经切好长度为 3 的绳子中拿出一段与长度为 1 的绳子重新组合把它们切成两段长度为 2 的绳子以下为证明过程
2020-11-17 00:32:18 +08:00
将绳子拆成 1 n-1 1(n-1)-n=-1\<0即拆开后的乘积一定更小所以不能出现长度为 1 的绳子
2020-11-05 02:09:40 +08:00
2020-11-17 00:32:18 +08:00
将绳子拆成 2 n-2 2(n-2)-n = n-4 n\>=4 时这样拆开能得到的乘积会比不拆更大
2020-11-05 02:09:40 +08:00
2020-11-17 00:32:18 +08:00
将绳子拆成 3 n-3 3(n-3)-n = 2n-9 n\>=5 时效果更好
2019-11-02 12:07:41 +08:00
2020-11-05 02:09:40 +08:00
将绳子拆成 4 n-4因为 4=2\*2因此效果和拆成 2 一样
2020-11-17 00:32:18 +08:00
将绳子拆成 5 n-5因为 5=2+3 5\<2\*3所以不能出现 5 的绳子而是尽可能拆成 2 3
2020-11-05 02:09:40 +08:00
2020-11-17 00:32:18 +08:00
将绳子拆成 6 n-6因为 6=3+3 6\<3\*3所以不能出现 6 的绳子而是拆成 3 3这里 6 同样可以拆成 6=2+2+2但是 3(n - 3) - 2(n - 2) = n - 5 \>= 0 n\>=5 的情况下将绳子拆成 3 比拆成 2 效果更好
2020-11-05 02:09:40 +08:00
继续拆成更大的绳子可以发现都比拆成 2 3 的效果更差因此我们只考虑将绳子拆成 2 3并且优先拆成 3当拆到绳子长度 n 等于 4 也就是出现 3+1此时只能拆成 2+2
2019-11-02 12:07:41 +08:00
```java
2021-03-23 02:48:19 +08:00
public int cutRope(int n) {
2019-11-02 12:07:41 +08:00
if (n < 2)
return 0;
if (n == 2)
return 1;
if (n == 3)
return 2;
int timesOf3 = n / 3;
if (n - timesOf3 * 3 == 1)
timesOf3--;
int timesOf2 = (n - timesOf3 * 3) / 2;
return (int) (Math.pow(3, timesOf3)) * (int) (Math.pow(2, timesOf2));
}
```
### 动态规划
```java
2021-03-23 02:48:19 +08:00
public int cutRope(int n) {
2019-11-02 12:07:41 +08:00
int[] dp = new int[n + 1];
dp[1] = 1;
for (int i = 2; i <= n; i++)
for (int j = 1; j < i; j++)
dp[i] = Math.max(dp[i], Math.max(j * (i - j), dp[j] * (i - j)));
return dp[n];
}
```