Commit on 2025/07/28 周一 21:28:40.93
This commit is contained in:
parent
3f0c608c84
commit
5d682e6b30
@ -2079,9 +2079,9 @@ public boolean canFillBackpack(int[] weights, int capacity) {
|
|||||||
dp[j] 表示从数组中选取若干个数,使得这些数的和正好为 j 的方法数。
|
dp[j] 表示从数组中选取若干个数,使得这些数的和正好为 j 的方法数。
|
||||||
|
|
||||||
状态转移:
|
状态转移:
|
||||||
对于数组中的每个数字 numnumnum,从 dp 数组后向前(逆序)遍历,更新:
|
对于数组中的每个数字 `num`,从 dp 数组后向前(逆序)遍历,更新:
|
||||||
|
|
||||||
dp[j]=dp[j]+dp[j−num]
|
`dp[j]=dp[j]+dp[j−num]`
|
||||||
|
|
||||||
这里的意思是:
|
这里的意思是:
|
||||||
|
|
||||||
@ -2102,7 +2102,7 @@ dp[j]=dp[j]+dp[j−num]
|
|||||||
|
|
||||||
#### 0/1背包(一)
|
#### 0/1背包(一)
|
||||||
|
|
||||||
描述:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。
|
描述:有n件物品和一个最多能背重量为 w 的背包。第 i 件物品的重量是 weight[i],得到的价值是 value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。
|
||||||
|
|
||||||
<img src="https://pic.bitday.top/i/2025/04/11/r292zm-0.png" alt="image-20250411163635562" style="zoom: 80%;" />
|
<img src="https://pic.bitday.top/i/2025/04/11/r292zm-0.png" alt="image-20250411163635562" style="zoom: 80%;" />
|
||||||
|
|
||||||
@ -2116,18 +2116,18 @@ dp[j]=dp[j]+dp[j−num]
|
|||||||
|
|
||||||
**2. 确定递推公式**
|
**2. 确定递推公式**
|
||||||
|
|
||||||
考虑dp\[i][j],有两种情况:
|
考虑 `dp[i][j]`,有两种情况:
|
||||||
|
|
||||||
- **不放物品i**:背包容量为j,里面不放物品i的最大价值是 dp\[i - 1][j]。
|
- **不放物品i**:背包容量为 `j` ,里面不放物品 `i` 的最大价值是 `dp[i - 1][j]`。
|
||||||
- **放物品i**:背包空出物品i的容量后,背包容量为 j - weight[i],dp\[i - 1][j - weight[i]] 为背包容量为j - weight[i]且不放物品i的最大价值,那么dp\[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值
|
- **放物品i**:背包空出物品i的容量后,背包容量为 `j - weight[i]`,`dp[i - 1][j - weight[i]]` 为背包容量为`j - weight[i]` 且不放物品i的最大价值,那么`dp[i - 1][j - weight[i]] + value[i]` (物品i的价值),就是背包放物品i得到的最大价值
|
||||||
|
|
||||||
递归公式: `dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);`
|
递归公式: `dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);`
|
||||||
|
|
||||||
**3. dp数组如何初始化**
|
**3. dp数组如何初始化**
|
||||||
|
|
||||||
(1)首先从dp\[i][j]的定义出发,如果背包容量j为0的话,即dp\[i][0],无论是选取哪些物品,背包价值总和一定为0。
|
(1)首先从 `dp[i][j]` 的定义出发,如果背包容量 `j` 为0的话,即 `dp[i][0]` ,无论是选取哪些物品,背包价值总和一定为0。
|
||||||
|
|
||||||
(2)由状态转移方程 `dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);` 可以看出i 是由 i-1 推导出来,那么i为0的时候就一定要初始化。
|
(2)由状态转移方程 `dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);` 可以看出`i` 是由 `i-1` 推导出来,那么 `i` 为0的时候就一定要初始化。
|
||||||
|
|
||||||
此时就看存放编号0的物品的时候,各个容量的背包所能存放的最大价值。
|
此时就看存放编号0的物品的时候,各个容量的背包所能存放的最大价值。
|
||||||
|
|
||||||
@ -2156,7 +2156,7 @@ for(int i = 1; i < weight.size(); i++) { // 遍历物品
|
|||||||
|
|
||||||
**代码:**
|
**代码:**
|
||||||
|
|
||||||
```
|
```java
|
||||||
public int knapsack(int[] weight, int[] value, int capacity) {
|
public int knapsack(int[] weight, int[] value, int capacity) {
|
||||||
int n = weight.length; // 物品的总个数
|
int n = weight.length; // 物品的总个数
|
||||||
|
|
||||||
@ -2202,11 +2202,11 @@ for(int i = 1; i < weight.size(); i++) { // 遍历物品
|
|||||||
|
|
||||||
1.状态转移只依赖于之前的状态(例如上一行或上一个层次),而不是当前行中动态更新的状态。
|
1.状态转移只依赖于之前的状态(例如上一行或上一个层次),而不是当前行中动态更新的状态。
|
||||||
|
|
||||||
- 例如在 0/1 背包问题中,二维 dp\[i][j] 只依赖于 dp\[i-1][j] 和 dp\[i-1][j - weight[i]]。
|
- 例如在 0/1 背包问题中,二维 `dp[i][j]` 只依赖于 `dp[i-1][j]` 和 `dp[i-1][j - weight[i]]`。
|
||||||
|
|
||||||
2.存在确定的遍历顺序(例如逆序或正序)能够确保在更新一维 dp 时,所依赖的值不会被当前更新覆盖。
|
2.存在确定的遍历顺序(例如逆序或正序)能够确保在更新一维 dp 时,所依赖的值不会被当前更新覆盖。
|
||||||
|
|
||||||
- **逆序遍历**:例如 0/1 背包问题,为了防止同一个物品被重复使用,需要对容量 j 从大到小遍历,确保 dp[j - weight] 的值还是上一轮(上一行)的。
|
- **逆序遍历**:例如 0/1 背包问题,为了防止同一个物品被重复使用,需要对容量 j 从大到小遍历,确保 `dp[j - weight]` 的值还是上一轮(上一行)的。
|
||||||
|
|
||||||
- **正序遍历**:在一些问题中,如果状态更新不会导致当前状态被重复利用(例如完全背包问题),可以顺序遍历。
|
- **正序遍历**:在一些问题中,如果状态更新不会导致当前状态被重复利用(例如完全背包问题),可以顺序遍历。
|
||||||
|
|
||||||
@ -2219,12 +2219,12 @@ for(int i = 1; i < weight.size(); i++) { // 遍历物品
|
|||||||
使用一维 dp 数组 `dp[j]` 表示「在当前考虑的物品下,背包容量为 j 时能够获得的最大价值」。
|
使用一维 dp 数组 `dp[j]` 表示「在当前考虑的物品下,背包容量为 j 时能够获得的最大价值」。
|
||||||
|
|
||||||
**2.确定递推公式**
|
**2.确定递推公式**
|
||||||
当考虑当前物品 i(重量为 weight[i],价值为 value[i])时,有两种选择:
|
当考虑当前物品 `i` (重量为 `weight[i]`,价值为 `value[i]`)时,有两种选择:
|
||||||
|
|
||||||
- **不选当前物品 i:**
|
- **不选当前物品 i:**
|
||||||
此时的最大价值为 dp[j](即前面的状态没有变化)。
|
此时的最大价值为 `dp[j]`(即前面的状态没有变化)。
|
||||||
- **选当前物品 i:**
|
- **选当前物品 i:**
|
||||||
当背包容量至少为 weight[i] 时,如果选择物品 i,剩余容量变为 j - weight[i],则最大价值为 dp[j - weight[i]] 加上 value[i]。
|
当背包容量至少为 `weight[i]` 时,如果选择物品 `i` ,剩余容量变为 `j - weight[i]`,则最大价值为 `dp[j - weight[i]]` 加上 `value[i]`。
|
||||||
|
|
||||||
因此,状态转移方程为:
|
因此,状态转移方程为:
|
||||||
$$
|
$$
|
||||||
@ -2234,7 +2234,7 @@ $$
|
|||||||
|
|
||||||
`dp[0] = 0`,表示当背包容量为 0 时,能获得的最大价值自然为 0。
|
`dp[0] = 0`,表示当背包容量为 0 时,能获得的最大价值自然为 0。
|
||||||
|
|
||||||
对于其他容量 dp[j],初始值也设为 0,dp数组在推导的时候一定是取价值最大的数,如果题目给的价值都是正整数那么非0下标都初始化为0就可以了。确保值不被初始值覆盖即可。
|
对于其他容量 `dp[j]` ,初始值也设为 0,dp数组在推导的时候一定是取价值最大的数,如果题目给的价值都是正整数那么非0下标都初始化为0就可以了。确保值不被初始值覆盖即可。
|
||||||
|
|
||||||
**4.一维dp数组遍历顺序**
|
**4.一维dp数组遍历顺序**
|
||||||
|
|
||||||
@ -2242,7 +2242,7 @@ $$
|
|||||||
|
|
||||||
内层遍历背包容量(**逆序遍历**): 遍历容量从 capacity 到当前物品的重量,进行状态更新。
|
内层遍历背包容量(**逆序遍历**): 遍历容量从 capacity 到当前物品的重量,进行状态更新。
|
||||||
|
|
||||||
- 逆序遍历的目的在于确保当前物品在更新过程中只会被使用一次,因为 dp[j - weight[i]] 代表的是上一轮(当前物品未使用前)的状态,不会被当前物品更新后的状态覆盖。
|
- 逆序遍历的目的在于确保当前物品在更新过程中只会被使用一次,因为 `dp[j - weight[i]]` 代表的是上一轮(当前物品未使用前)的状态,不会被当前物品更新后的状态覆盖。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2308,7 +2308,7 @@ dp\[i][j] 表示从下标为[0-i]的物品,每个物品可以取无限次,
|
|||||||
**2. 确定递推公式**
|
**2. 确定递推公式**
|
||||||
|
|
||||||
- **不放物品i**:背包容量为j,里面不放物品i的最大价值是dp\[i - 1][j]。
|
- **不放物品i**:背包容量为j,里面不放物品i的最大价值是dp\[i - 1][j]。
|
||||||
- **放物品i**:背包空出物品i的容量后,背包容量为j - weight[i],dp\[i][j - weight[i]] 为背包容量为j - weight[i]且不放物品i的最大价值,那么dp\[i][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值
|
- **放物品i**:背包空出物品i的容量后,背包容量为`j - weight[i]`,`dp[i][j - weight[i]]` 为背包容量为`j - weight[i]`且不放物品i的最大价值,那么`dp[i][j - weight[i]] + value[i]` (物品i的价值),就是背包放物品i得到的最大价值
|
||||||
|
|
||||||
递推公式: `dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);`
|
递推公式: `dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);`
|
||||||
|
|
||||||
@ -2318,17 +2318,18 @@ dp\[i][j] 表示从下标为[0-i]的物品,每个物品可以取无限次,
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
for (int i = 1; i < n; i++) {
|
for (int i = 1; i < n; i++) {
|
||||||
for (int j = 0; j <= capacity; j++) {
|
for (int j = 0; j <= capacity; j++) {
|
||||||
// 不选物品 i,价值不变
|
// 不选物品 i,价值不变
|
||||||
dp[i][j] = dp[i - 1][j];
|
dp[i][j] = dp[i - 1][j];
|
||||||
// 如果当前背包容量 j 能放下物品 i,则考虑选取物品 i(完全背包内层循环正序或逆序都可以,但这里通常建议正序)
|
// 如果当前背包容量 j 能放下物品 i,则考虑选取物品 i(完全背包内层循环正序或逆序都可以,但这里通常建议正序)
|
||||||
if (j >= weight[i]) {
|
if (j >= weight[i]) {
|
||||||
// 注意:这里选取物品 i 后仍然可以继续选取物品 i,
|
// 注意:这里选取物品 i 后仍然可以继续选取物品 i,
|
||||||
// 所以状态转移方程为 dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i])
|
// 所以状态转移方程为 dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i])
|
||||||
dp[i][j] = Math.max(dp[i][j], dp[i][j - weight[i]] + value[i]);
|
dp[i][j] = Math.max(dp[i][j], dp[i][j - weight[i]] + value[i]);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. dp数组如何初始化**
|
**3. dp数组如何初始化**
|
||||||
@ -2338,13 +2339,13 @@ for (int i = 1; i < n; i++) {
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
for (int j = 0; j <= capacity; j++) {
|
for (int j = 0; j <= capacity; j++) {
|
||||||
// 当 j 小于第 0 个物品重量时,无法选取,所以价值为 0
|
// 当 j 小于第 0 个物品重量时,无法选取,所以价值为 0
|
||||||
if (j < weight[0]) {
|
if (j < weight[0]) {
|
||||||
dp[0][j] = 0;
|
dp[0][j] = 0;
|
||||||
} else {
|
} else {
|
||||||
// 完全背包允许多次使用物品 0,所以递归地累加
|
// 完全背包允许多次使用物品 0,所以递归地累加
|
||||||
dp[0][j] = dp[0][j - weight[0]] + value[0];
|
dp[0][j] = dp[0][j - weight[0]] + value[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -2362,12 +2363,32 @@ for (int j = 0; j <= capacity; j++) {
|
|||||||
|
|
||||||
压缩成一维,即`dp[j] = max(dp[j], dp[j - weight[i]] + value[i])`
|
压缩成一维,即`dp[j] = max(dp[j], dp[j - weight[i]] + value[i])`
|
||||||
|
|
||||||
- 根据题型选择先遍历物品或者背包,**如果求组合数就是外层for循环遍历物品,内层for遍历背包**。**如果求排列数就是外层for遍历背包,内层for循环遍历物品**。
|
- 根据题型选择先遍历物品或者背包,
|
||||||
**组合不强调元素之间的顺序,排列强调元素之间的顺序**。
|
**如果求组合数就是外层for循环遍历物品,内层for遍历背包**。
|
||||||
|
**如果求排列数就是外层for遍历背包,内层for循环遍历物品**。
|
||||||
|
**组合数**(顺序不同的序列视为相同)**排列数**(顺序不同的序列视为不同)排列数大于等于组合数!!!。
|
||||||
- 内层循环正序,不要逆序!因为要利用已经更新的dp数组,允许同一物品重复使用!
|
- 内层循环正序,不要逆序!因为要利用已经更新的dp数组,允许同一物品重复使用!
|
||||||
|
|
||||||
注意,完全背包和0/1背包的一维dp形式的递推公式一样,但是遍历顺序不同!!
|
注意,完全背包和0/1背包的一维dp形式的递推公式一样,但是遍历顺序不同!!
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int completeKnapsack(int[] weight, int[] value, int capacity) {
|
||||||
|
int n = weight.length;
|
||||||
|
// dp[j] 表示容量为 j 时的最大价值,初始化为 0
|
||||||
|
int[] dp = new int[capacity + 1];
|
||||||
|
|
||||||
|
// 遍历每件物品
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
// 完全背包:正序遍历容量
|
||||||
|
for (int j = weight[i]; j <= capacity; j++) {
|
||||||
|
// 如果拿 i 号物品,更新 dp[j]
|
||||||
|
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[capacity];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 多重背包
|
#### 多重背包
|
||||||
|
152
杂项/mermaid画图.md
Normal file
152
杂项/mermaid画图.md
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# mermaid画图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[多智能体随机网络结构分析] --> B[多智能体协同学习与推理]
|
||||||
|
|
||||||
|
A --> A1["谱参数实时估算"]
|
||||||
|
A1 --> A11["卡尔曼滤波"]
|
||||||
|
A1 --> A12["矩阵扰动理论"]
|
||||||
|
A1 --> A13["输出:谱参数"]
|
||||||
|
A --> A2["网络拓扑重构"]
|
||||||
|
A2 --> A21["低秩分解重构"]
|
||||||
|
A2 --> A22["聚类量化"]
|
||||||
|
A2 --> A23["输出:邻接矩阵、特征矩阵"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
B[多智能体协同学习与推理]
|
||||||
|
B --> B1["联邦学习、强化学习"]
|
||||||
|
B1 --> B11["谱驱动学习率调整"]
|
||||||
|
B1 --> B12["自适应节点选择策略"]
|
||||||
|
B --> B2["动态图神经网络"]
|
||||||
|
B2 --> B21["动态图卷积设计"]
|
||||||
|
B2 --> B22["一致性推理"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
%% 颜色和样式定义
|
||||||
|
classDef startEnd fill:#e6ffe6,stroke:#333,stroke-width:2px
|
||||||
|
classDef operation fill:#fff,stroke:#000,stroke-width:1px
|
||||||
|
classDef decision fill:#ffcccc,stroke:#000,stroke-width:1px
|
||||||
|
classDef update fill:#ccffcc,stroke:#000,stroke-width:1px
|
||||||
|
|
||||||
|
%% 节点定义(严格按图片顺序)
|
||||||
|
A([开始]):::startEnd
|
||||||
|
B[交易信息\n外部订单号]:::operation
|
||||||
|
C{判断是否为锁单订单}:::decision
|
||||||
|
D[查询拼团组队信息]:::operation
|
||||||
|
E[更新订单详情\n状态为交易完成]:::update
|
||||||
|
F[更新拼团组队进度]:::update
|
||||||
|
G{拼团组队完结\n目标量判断}:::decision
|
||||||
|
H[写入回调任务表]:::operation
|
||||||
|
I([结束]):::startEnd
|
||||||
|
|
||||||
|
%% 流程连接(完全还原图片走向)
|
||||||
|
A --> B
|
||||||
|
B --> C
|
||||||
|
C -->|是| D
|
||||||
|
D --> E
|
||||||
|
E --> F
|
||||||
|
F --> G
|
||||||
|
G -->|是| H
|
||||||
|
H --> I
|
||||||
|
C -->|否| I
|
||||||
|
G -->|否| I
|
||||||
|
|
||||||
|
%% 保持原图连接线样式
|
||||||
|
linkStyle 0,1,2,3,4,5,6,7,8 stroke-width:1px
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[用户发起退单请求] --> B{检查拼团状态}
|
||||||
|
|
||||||
|
B -->|拼团未完成| C1[场景1:拼团中退单]
|
||||||
|
C1 --> D1{是否已支付?}
|
||||||
|
D1 -->|未支付| E1[取消订单]
|
||||||
|
E1 --> F1[更新订单状态为2]
|
||||||
|
F1 --> G1[通知拼团失败]
|
||||||
|
G1 --> H1[退单完成]
|
||||||
|
D1 -->|已支付| I1[发起退款]
|
||||||
|
I1 --> F1
|
||||||
|
|
||||||
|
B -->|拼团已完成| C2[场景2:完成后退单]
|
||||||
|
C2 --> D2{是否超时限?}
|
||||||
|
D2 -->|未超时| E2[发起退款]
|
||||||
|
E2 --> F2[更新订单状态]
|
||||||
|
F2 --> H1
|
||||||
|
D2 -->|超时| G2[退单失败]
|
||||||
|
|
||||||
|
style A fill:#f9f,stroke:#333
|
||||||
|
style B fill:#66f,stroke:#333
|
||||||
|
style C1 fill:#fbb,stroke:#f66
|
||||||
|
style C2 fill:#9f9,stroke:#090
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
%% ===================== 左侧:模板模式块 =====================
|
||||||
|
subgraph Template["设计模式 - 模板"]
|
||||||
|
direction TB
|
||||||
|
SM["StrategyMapper
|
||||||
|
策略映射器"]
|
||||||
|
SH["StrategyHandler
|
||||||
|
策略处理器"]
|
||||||
|
ASR["AbstractStrategyRouter<T, D, R>
|
||||||
|
策略路由抽象类"]
|
||||||
|
|
||||||
|
SM -->|实现| ASR
|
||||||
|
SH -->|实现| ASR
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ===================== 右侧:策略工厂与支持类 =====================
|
||||||
|
DASFactory["DefaultActivityStrategyFactory
|
||||||
|
默认的拼团活动策略工厂"]
|
||||||
|
AGMS["AbstractGroupBuyMarketSupport
|
||||||
|
功能服务支撑类"]
|
||||||
|
|
||||||
|
DASFactory --> AGMS
|
||||||
|
AGMS -->|继承| ASR
|
||||||
|
|
||||||
|
%% ===================== 业务节点链路 =====================
|
||||||
|
Root["RootNode
|
||||||
|
根节点"]
|
||||||
|
Switch["SwitchRoot
|
||||||
|
开关节点"]
|
||||||
|
Market["MarketNode
|
||||||
|
营销节点"]
|
||||||
|
End["EndNode
|
||||||
|
结尾节点"]
|
||||||
|
Other["其他节点"]
|
||||||
|
|
||||||
|
AGMS --> Root
|
||||||
|
Root --> Switch
|
||||||
|
Switch --> Market
|
||||||
|
Market --> End
|
||||||
|
Switch -.-> Other
|
||||||
|
Other --> End
|
||||||
|
|
||||||
|
%% ===================== 样式(可选) =====================
|
||||||
|
classDef green fill:#DFF4E3,stroke:#3B7A57,stroke-width:1px;
|
||||||
|
classDef red fill:#E74C3C,color:#fff,stroke:#B03A2E;
|
||||||
|
classDef purple fill:#7E60A2,color:#fff,stroke:#4B3B6B;
|
||||||
|
classDef blue fill:#3DA9F5,color:#fff,stroke:#1B6AA5;
|
||||||
|
|
||||||
|
class SM,SH,Root,Switch,Market,End,Other green;
|
||||||
|
class DASFactory red;
|
||||||
|
class AGMS purple;
|
||||||
|
class ASR blue;
|
||||||
|
|
||||||
|
style Template stroke-dasharray: 5 5;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -1,32 +0,0 @@
|
|||||||
# mermaid画图
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
A[多智能体随机网络结构分析] --> B[多智能体协同学习与推理]
|
|
||||||
|
|
||||||
A --> A1["谱参数实时估算"]
|
|
||||||
A1 --> A11["卡尔曼滤波"]
|
|
||||||
A1 --> A12["矩阵扰动理论"]
|
|
||||||
A1 --> A13["输出:谱参数"]
|
|
||||||
A --> A2["网络拓扑重构"]
|
|
||||||
A2 --> A21["低秩分解重构"]
|
|
||||||
A2 --> A22["聚类量化"]
|
|
||||||
A2 --> A23["输出:邻接矩阵、特征矩阵"]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
B[多智能体协同学习与推理]
|
|
||||||
B --> B1["联邦学习、强化学习"]
|
|
||||||
B1 --> B11["谱驱动学习率调整"]
|
|
||||||
B1 --> B12["自适应节点选择策略"]
|
|
||||||
B --> B2["动态图神经网络"]
|
|
||||||
B2 --> B21["动态图卷积设计"]
|
|
||||||
B2 --> B22["一致性推理"]
|
|
||||||
```
|
|
||||||
|
|
177
项目/拼团交易系统.md
177
项目/拼团交易系统.md
@ -115,8 +115,6 @@ crowd_tags_job 人群标签任务
|
|||||||
| create_time | 创建时间 |
|
| create_time | 创建时间 |
|
||||||
| update_time | 更新时间 |
|
| update_time | 更新时间 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- 拼团活动表:设定了拼团的成团规则,人群标签的使用可以限定哪些人可见,哪些人可参与。
|
- 拼团活动表:设定了拼团的成团规则,人群标签的使用可以限定哪些人可见,哪些人可参与。
|
||||||
- 折扣配置表:拆分出拼团优惠到一个新的表进行多条配置。如果折扣还有更多的复杂规则,则可以配置新的折扣规则表进行处理。
|
- 折扣配置表:拆分出拼团优惠到一个新的表进行多条配置。如果折扣还有更多的复杂规则,则可以配置新的折扣规则表进行处理。
|
||||||
- 人群标签表:专门来做人群设计记录的,这3张表就是为了把符合规则的人群ID,也就是用户ID,全部跑任务到一个记录下进行使用。比如黑玫瑰人群、高净值人群、拼团履约率90%以上的人群等。
|
- 人群标签表:专门来做人群设计记录的,这3张表就是为了把符合规则的人群ID,也就是用户ID,全部跑任务到一个记录下进行使用。比如黑玫瑰人群、高净值人群、拼团履约率90%以上的人群等。
|
||||||
@ -313,7 +311,7 @@ EndNode.apply() → 组装结果并返回 TrialBalanceEntity
|
|||||||
|
|
||||||
## 拼团结算
|
## 拼团结算
|
||||||
|
|
||||||
<img src="https://pic.bitday.top/i/2025/07/15/p876v1-0.png" alt="d56fcfb9708eb0d99600c751808bb843" style="zoom:80%;" />
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -376,6 +374,51 @@ EndNode.apply() → 组装结果并返回 TrialBalanceEntity
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 逆向工程:退单
|
||||||
|
|
||||||
|
<img src="https://pic.bitday.top/i/2025/07/25/hgggjo-0.png" alt="image-20250725105608390" style="zoom:67%;" />
|
||||||
|
|
||||||
|
逆向的流程,要分析用户是在哪个流程节点下进行中断行为。包括3个场景;
|
||||||
|
|
||||||
|
**已锁单、未支付**
|
||||||
|
|
||||||
|
- **用户行为**:完成锁单后未发起支付。
|
||||||
|
- **结果**:订单超时自动关单。
|
||||||
|
- 补偿
|
||||||
|
- 若用户在临界时刻支付,则需执行“逆向退款”流程——退还支付金额并告知“优惠已过期,请重新参与”。
|
||||||
|
- 否则该订单自动失效,释放拼团名额给后续用户。
|
||||||
|
|
||||||
|
**已锁单、已支付,但拼团未成团**
|
||||||
|
|
||||||
|
- **用户行为**:完成支付,组团人数不足暂未成团。
|
||||||
|
|
||||||
|
- 补偿策略
|
||||||
|
|
||||||
|
(可配置优先级):
|
||||||
|
|
||||||
|
1. **先退拼团,再退款,**
|
||||||
|
2. **先退款,再退拼团**
|
||||||
|
|
||||||
|
- 具体执行哪种方式,可由拼团活动策略决定——“优先保障个人”或“优先保障成团”。
|
||||||
|
|
||||||
|
**已锁单、已支付,且拼团已成团**
|
||||||
|
|
||||||
|
- **用户行为**:支付成功,且组团人数已凑齐。
|
||||||
|
- 补偿流程
|
||||||
|
- 先退还用户支付金额;
|
||||||
|
- 再撤销对应的拼团完成量。
|
||||||
|
- **注意**:已成团订单视为“已完成含退单”,仍然成团、不再开放新用户参与,确保团队成团状态一致。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 策略模板应用
|
||||||
|
|
||||||
|
根据订单状态和拼团状态动态选择退单策略。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 收获
|
## 收获
|
||||||
|
|
||||||
### 实体对象
|
### 实体对象
|
||||||
@ -727,7 +770,7 @@ while 循环:
|
|||||||
|
|
||||||
### 规则树流程
|
### 规则树流程
|
||||||
|
|
||||||

|
!
|
||||||
|
|
||||||
**整体分层思路**
|
**整体分层思路**
|
||||||
|
|
||||||
@ -814,10 +857,10 @@ private Map<String, IDiscountCalculateService> discountCalculateServiceMap;
|
|||||||
|
|
||||||
**字段类型**:`Map<String, IDiscountCalculateService>`
|
**字段类型**:`Map<String, IDiscountCalculateService>`
|
||||||
|
|
||||||
- key—— Bean 的名字
|
- key—— **Bean 的名字**
|
||||||
- 默认是类名首字母小写 (`mjCalculateService`)
|
- 默认是类名首字母小写 (`mjCalculateService`)
|
||||||
- 或者你在实现类上显式写的 `@Service("MJ")`
|
- 或者你在实现类上显式写的 `@Service("MJ")`
|
||||||
- **value** —— 那个实现类对应的实例
|
- **value** —— 那个实现类对应的**实例**
|
||||||
- **Spring 机制**:
|
- **Spring 机制**:
|
||||||
1. 启动时扫描所有实现 `IDiscountCalculateService` 的 Bean。
|
1. 启动时扫描所有实现 `IDiscountCalculateService` 的 Bean。
|
||||||
2. 把它们按 “BeanName → Bean 实例” 的映射注入到这张 `Map` 里。
|
2. 把它们按 “BeanName → Bean 实例” 的映射注入到这张 `Map` 里。
|
||||||
@ -1624,3 +1667,125 @@ List<Product> list = getFromCacheOrDb(
|
|||||||
| 运维依赖 | **无**:不依赖外部组件 | **有**:需维护高可用的 Redis 集群,增加运维成本 |
|
| 运维依赖 | **无**:不依赖外部组件 | **有**:需维护高可用的 Redis 集群,增加运维成本 |
|
||||||
|
|
||||||
目前本项目使用的是分布式限流,用Redisson
|
目前本项目使用的是分布式限流,用Redisson
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 日志系统
|
||||||
|
|
||||||
|
#### 输出流向一览
|
||||||
|
|
||||||
|
输出到3个地方:控制台、本地文件、ELK日志(服务器上内存不足无法部署!)
|
||||||
|
|
||||||
|
| 日志级别 | 控制台 | 本地文件(异步) | Logstash (TCP) |
|
||||||
|
| ----------- | ------ | ----------------------------- | -------------- |
|
||||||
|
| TRACE/DEBUG | — | — | — |
|
||||||
|
| INFO | ✔ | `log_info.log` | ✔ |
|
||||||
|
| WARN | ✔ | `log_info.log``log_error.log` | ✔ |
|
||||||
|
| ERROR/FATAL | ✔ | `log_info.log``log_error.log` | ✔ |
|
||||||
|
|
||||||
|
> 注意:实际写文件时,都是通过 ASYNC_FILE_INFO/ERROR 两个异步 Appender 执行,以免日志写盘阻塞业务线程。
|
||||||
|
|
||||||
|
#### ELK日志系统
|
||||||
|
|
||||||
|
本地文件每台机器都会在自己 `/data/log/...` 目录下滚动输出自己的日志,互相之间不会合并。
|
||||||
|
|
||||||
|
如果你希望跨多台服务器**统一管理**,就需要把日志推到中央端——ELK日志系统
|
||||||
|
|
||||||
|
ELK=Elasticsearch(存储&检索)+ Logstash(采集&处理)+ Kibana(可视化)
|
||||||
|
|
||||||
|
docker-compose.yml:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
elasticsearch:
|
||||||
|
image: elasticsearch:7.17.28
|
||||||
|
ports: ['9201:9200','9300:9300']
|
||||||
|
environment:
|
||||||
|
- discovery.type=single-node
|
||||||
|
- ES_JAVA_OPTS=-Xms512m -Xmx512m
|
||||||
|
volumes:
|
||||||
|
- ./data:/usr/share/elasticsearch/data
|
||||||
|
logstash:
|
||||||
|
image: logstash:7.17.28
|
||||||
|
ports: ['4560:4560','9600:9600']
|
||||||
|
volumes:
|
||||||
|
- ./logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
|
||||||
|
environment:
|
||||||
|
- LS_JAVA_OPTS=-Xms1g -Xmx1g
|
||||||
|
kibana:
|
||||||
|
image: kibana:7.17.28
|
||||||
|
ports: ['5601:5601']
|
||||||
|
environment:
|
||||||
|
- elasticsearch.hosts=http://elasticsearch:9200
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
kibana配置:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
#
|
||||||
|
# ** THIS IS AN AUTO-GENERATED FILE **
|
||||||
|
#
|
||||||
|
|
||||||
|
# Default Kibana configuration for docker target
|
||||||
|
server.host: "0"
|
||||||
|
server.shutdownTimeout: "5s"
|
||||||
|
elasticsearch.hosts: [ "http://elasticsearch:9200" ] # 记得修改ip
|
||||||
|
monitoring.ui.container.elasticsearch.enabled: true
|
||||||
|
i18n.locale: "zh-CN"
|
||||||
|
```
|
||||||
|
|
||||||
|
logstash配置:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
input {
|
||||||
|
tcp {
|
||||||
|
mode => "server"
|
||||||
|
host => "0.0.0.0"
|
||||||
|
port => 4560
|
||||||
|
codec => json_lines
|
||||||
|
type => "info"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filter {}
|
||||||
|
output {
|
||||||
|
elasticsearch {
|
||||||
|
action => "index"
|
||||||
|
hosts => "es:9200"
|
||||||
|
index => "group-buy-market-log-%{+YYYY.MM.dd}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
自己的项目:
|
||||||
|
|
||||||
|
```java
|
||||||
|
<!-- 上报日志;ELK -->
|
||||||
|
<springProperty name="LOG_STASH_HOST" scope="context" source="logstash.host" defaultValue="127.0.0.1"/>
|
||||||
|
|
||||||
|
<!--输出到logstash的appender-->
|
||||||
|
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
|
||||||
|
<!--可以访问的logstash日志收集端口-->
|
||||||
|
<destination>${LOG_STASH_HOST}:4560</destination>
|
||||||
|
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
|
||||||
|
</appender>
|
||||||
|
```
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.logstash.logback</groupId>
|
||||||
|
<artifactId>logstash-logback-encoder</artifactId>
|
||||||
|
<version>7.3</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用**
|
||||||
|
|
||||||
|
检查索引:curl http://localhost:9201/_cat/indices?v3
|
||||||
|
|
||||||
|
打开 Kibana:浏览器访问 `http://localhost:5601`,新建 索引模式(如 `app-log-*`),即可在 Discover/Visualize 中查看与分析日志。
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user