This commit is contained in:
programmercarl
2024-08-06 11:26:17 +08:00
parent 1865b7d198
commit 268c5b2adc
5 changed files with 313 additions and 15 deletions

View File

@ -42,7 +42,8 @@
我以[1,2,3]为例,抽象成树形结构如下:
![46.全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20211027181706.png)
![全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20240803180318.png)
### 回溯三部曲
@ -54,7 +55,7 @@
但排列问题需要一个used数组标记已经选择的元素如图橘黄色部分所示:
![46.全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20211027181706.png)
![全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20240803180318.png)
代码如下:
@ -66,7 +67,7 @@ void backtracking (vector<int>& nums, vector<bool>& used)
* 递归终止条件
![46.全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20201209174225145.png)
![全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20240803180318.png)
可以看出叶子节点,就是收割结果的地方。

View File

@ -134,17 +134,17 @@ x = (target + sum) / 2
大家看到(target + sum) / 2 应该担心计算的过程中向下取整有没有影响。
这么担心就对了例如sum 是5S是2的话其实就是无解的所以
这么担心就对了例如sum是5target是2 的话其实就是无解的,所以:
```CPP
C++代码中输入的S 就是题目描述的 target
if ((S + sum) % 2 == 1) return 0; // 此时没有方案
if ((target + sum) % 2 == 1) return 0; // 此时没有方案
```
同时如果 S的绝对值已经大于sum那么也是没有方案的。
同时如果target 的绝对值已经大于sum那么也是没有方案的。
```CPP
C++代码中输入的S 就是题目描述的 target
if (abs(S) > sum) return 0; // 此时没有方案
if (abs(target) > sum) return 0; // 此时没有方案
```
再回归到01背包问题为什么是01背包呢
@ -213,9 +213,9 @@ dp[j]其他下标对应的数值也应该初始化为0从递推公式也可
5. 举例推导dp数组
输入nums: [1, 1, 1, 1, 1], S: 3
输入nums: [1, 1, 1, 1, 1], target: 3
bagSize = (S + sum) / 2 = (3 + 5) / 2 = 4
bagSize = (target + sum) / 2 = (3 + 5) / 2 = 4
dp数组状态变化如下
@ -226,12 +226,12 @@ C++代码如下:
```CPP
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (abs(S) > sum) return 0; // 此时没有方案
if ((S + sum) % 2 == 1) return 0; // 此时没有方案
int bagSize = (S + sum) / 2;
if (abs(target) > sum) return 0; // 此时没有方案
if ((target + sum) % 2 == 1) return 0; // 此时没有方案
int bagSize = (target + sum) / 2;
vector<int> dp(bagSize + 1, 0);
dp[0] = 1;
for (int i = 0; i < nums.size(); i++) {
@ -655,3 +655,52 @@ public class Solution
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (abs(target) > sum) return 0; // 此时没有方案
if ((target + sum) % 2 == 1) return 0; // 此时没有方案
int bagSize = (target + sum) / 2;
vector<vector<int>> dp(nums.size(), vector<int>(bagSize + 1, 0));
if (nums[0] <= bagSize) dp[0][nums[0]] = 1;
dp[0][0] = 1;
int numZero = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == 0) numZero++;
dp[i][0] = (int) pow(2.0, numZero);
}
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j <= bagSize; j++) {
if (nums[i] > j) dp[i][j] = dp[i - 1][j];
else dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]];
}
}
for (int i = 0; i < nums.size(); i++) {
for (int j = 0; j <= bagSize; j++) {
cout << dp[i][j] << " ";
}
cout << endl;
}
return dp[nums.size() - 1][bagSize];
}
};
1 1 0 0 0
1 2 1 0 0
1 3 3 1 0
1 4 6 4 1
1 5 10 10 5
初始化 如果没有0 dp[i][0] = 1; 即所有元素都不取
用元素 取与不取来举例

View File

@ -64,7 +64,7 @@
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240328104119.png)
本图中,对所有边进行松弛,真正有效的松弛,只有松弛 边节点1->节点2 和 边节点1->节点5
本图中,对所有边进行松弛,真正有效的松弛,只有松弛 边节点1->节点2 和 边节点1->节点3
而松弛 边节点4->节点6 节点5->节点3等等 都是无效的操作,因为 节点4 和 节点 5 都是没有被计算过的节点。

View File

@ -0,0 +1,127 @@
# 151. 手机流畅运行的秘密
[题目链接](https://kamacoder.com/problempage.php?pid=1229)
先运行 能留下电量多的 任务,才能有余电运行其他任务。
任务11:10 ,运行完 能留下 9个电
任务22:12运行完 能留下 10个电
任务33:10运行完 能留下 7个电。
运行顺序: 任务2 -> 任务1 -> 任务3
按照 最低初始电量 - 耗电量,从大到小排序。
计算总电量,需要 从小到大 遍历, 不断取 总电量 + 任务耗电量 与 任务最低初始电量 的最大值。
```CPP
#include<bits/stdc++.h>
using namespace std;
bool cmp(const pair<int,int>& taskA, const pair<int,int>& taskB) {
return (taskA.second - taskA.first) < (taskB.second - taskB.first);
}
int main() {
string str, tmp;
vector<pair<int,int>> tasks;
//处理输入
getline(cin, str);
stringstream ss(str);
while (getline(ss, tmp, ',')) {
int p = tmp.find(":");
string a = tmp.substr(0, p);
string b = tmp.substr(p + 1);
tasks.push_back({stoi(a), stoi(b)});
}
// 按照差值从小到大排序
sort(tasks.begin(), tasks.end(), cmp);
// 收集结果
int result = 0;
for (int i = 0 ; i < tasks.size(); i++) {
result = max(result + tasks[i].first, tasks[i].second);
}
result = result <= 4800 ? result : -1;
cout << result << endl;
}
```
Java版本
```Java
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String[] tasksArray = str.split(",");
List<Pair> tasks = Arrays.stream(tasksArray)
.map(task -> {
String[] parts = task.split(":");
return new Pair(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
})
.collect(Collectors.toList());
// 按照差值从小到大排序
Collections.sort(tasks, (taskA, taskB) ->
(taskA.second - taskA.first) - (taskB.second - taskB.first)
);
// 收集结果
int result = 0;
for (Pair task : tasks) {
result = Math.max(result + task.first, task.second);
}
result = result <= 4800 ? result : -1;
System.out.println(result);
}
}
class Pair {
int first;
int second;
Pair(int first, int second) {
this.first = first;
this.second = second;
}
}
```
Python版本
```python
def main():
import sys
input = sys.stdin.read
str = input().strip()
tasks = []
for tmp in str.split(','):
a, b = map(int, tmp.split(':'))
tasks.append((a, b))
# 按照差值从小到大排序
tasks.sort(key=lambda task: task[1] - task[0])
# 收集结果
result = 0
for task in tasks:
result = max(result + task[0], task[1])
result = result if result <= 4800 else -1
print(result)
if __name__ == "__main__":
main()
```

View File

@ -0,0 +1,121 @@
# 152. 小米手机通信校准
[题目链接](https://kamacoder.com/problempage.php?pid=1230)
一道模拟题,但比较考察 代码能力。
遍历去找 里 freq 最近的 freg就好 需要记录刚遍历过的的freg和 loss因为可能有 相邻一样的 freg。
```CPP
#include <bits/stdc++.h>
using namespace std;
int main() {
int freq;
cin >> freq;
string data;
double result = 0;
int last_freg = 0; // 记录上一个 freg
int last_loss = 0; // 记录上一个loss
while(cin >> data) {
int index = data.find(':');
int freg = stoi(data.substr(0, index)); // 获取 freg 和 loss
int loss = stoi(data.substr(index + 1));
// 两遍一样
if(abs(freg - freq) == abs(last_freg - freq)) {
result = (double)(last_loss + loss)/2.0;
} // 否则更新最新的result
else if(abs(freg - freq) < abs(last_freg - freq)){
result = (double)loss;
}
last_freg = freg;
last_loss = loss;
}
printf("%.1lf\n", result);
return 0;
}
```
Java 版本:
```Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int freq = sc.nextInt();
sc.nextLine(); // 读取换行符
String inputLine = sc.nextLine(); // 读取包含所有后续输入的行
String[] data = inputLine.split(" "); // 根据空格分割输入
double result = 0;
int lastFreq = 0; // 记录上一个 freg
int lastLoss = 0; // 记录上一个 loss
for (String entry : data) {
int index = entry.indexOf(':');
int freg = Integer.parseInt(entry.substring(0, index)); // 获取 freg 和 loss
int loss = Integer.parseInt(entry.substring(index + 1));
// 两遍一样
if (Math.abs(freg - freq) == Math.abs(lastFreq - freq)) {
result = (double) (lastLoss + loss) / 2.0;
}
// 否则更新最新的 result
else if (Math.abs(freg - freq) < Math.abs(lastFreq - freq)) {
result = (double) loss;
}
lastFreq = freg;
lastLoss = loss;
}
System.out.printf("%.1f\n", result);
sc.close();
}
}
```
Python版本
```python
def main():
import sys
input = sys.stdin.read
data = input().split()
freq = int(data[0])
result = 0
last_freg = 0 # 记录上一个 freg
last_loss = 0 # 记录上一个 loss
for i in range(1, len(data)):
item = data[i]
index = item.find(':')
freg = int(item[:index]) # 获取 freg 和 loss
loss = int(item[index + 1:])
# 两遍一样
if abs(freg - freq) == abs(last_freg - freq):
result = (last_loss + loss) / 2.0
# 否则更新最新的 result
elif abs(freg - freq) < abs(last_freg - freq):
result = loss
last_freg = freg
last_loss = loss
print(f"{result:.1f}")
if __name__ == "__main__":
main()
```