【深度优先搜索篇】走迷宫的魔法:算法如何破解迷宫的神秘密码

                                    当你在夜晚孤军奋战时,满天星光以为你而闪烁。                                        

99e2905db4694bacac18f4cc52776b9e.png 

欢迎拜访羑悻的小杀马特.-CSDN博客

本篇主题:轻轻松松拿捏洛谷走迷宫问题

制作日期:2024.12.31

隶属专栏:C/C++题海汇总

 ec0ff165e5eb4f3faff5b940f7c8d876.gif

69eed4dd995743a394cab61a26841d4f.jpeg 

首先我们先进行对深搜及走迷宫进行一下了解之后在以例题深入:

 

目录

一·前言:

1.1深度优先搜索概述:

基本思想:

1.2走迷宫问题的应用场景:

 问题描述:

1.3DFS 解决走迷宫问题的实现步骤:

1.3.1数据结构准备:

1.3.2递归函数定义:

1.3.3搜索过程:

1.4优缺点:

 1.4.1优点:

1.4.2缺点:

1.5代码展示及其解释:

 二·走迷宫例题:

 三·分析操作:

细节处理:

 四·代码展示:

其他类似解法: 

五·本篇小结:


 

一·前言:

1.1深度优先搜索概述:

基本思想:

DFS 是一种用于遍历或搜索树或图的算法。它从根节点(对于图,可能是任意一个节点)开始,沿着一条路径尽可能深地访问节点,直到无法继续为止,然后回溯到上一个未完全探索的节点,继续搜索未访问的分支。

 

 

在搜索过程中,它使用栈(通常是递归调用栈)来存储待访问的节点信息,体现了后进先出(LIFO)的原则。

1.2走迷宫问题的应用场景:

 问题描述:

走迷宫问题通常可以抽象为一个二维矩阵,其中某些单元表示墙壁(不可通行),其他单元表示通道(可通行)。目标是从起点找到一条到达终点的路径。

 例如,一个mxn  的矩阵,用 0 表示通道,1 表示墙壁,需要找到从起点  (a,b)到终点(c,d ) 的可行路径。

1.3DFS 解决走迷宫问题的实现步骤:

1.3.1数据结构准备

①迷宫表示:使用二维数组 maze[m][n] 存储迷宫的布局,0 或 1 表示通道或墙壁。

②标记数组:使用 visited[m][n] 标记节点是否已访问,避免重复访问。

③方向数组:使用 dx[] 和 dy[] 表示上下左右四个方向的偏移量,如 dx = {-1, 0, 1, 0}dy = {0, 1, 0, -1},表示上、右、下、左四个方向的坐标变化。

1.3.2递归函数定义

①dfs(int x, int y) 是核心递归函数,其中 x 和 y 表示当前节点的坐标。

②函数首先检查当前节点是否为终点,如果是则表示找到路径;然后检查是否越界、是否是墙壁或已访问,如果都不是,则标记为已访问,并递归调用 dfs 函数对相邻节点进行搜索。

1.3.3搜索过程:

①从起点开始调用 dfs(start_x, start_y)

②对于当前节点 (x, y),依次尝试向四个方向移动(根据 dx 和 dy),并对满足条件(未越界、不是墙壁、未访问)的新节点调用 dfs 函数。

③如果某一方向的递归调用找到了路径,返回 true,否则回溯,将当前节点标记为未访问(即取消标记),尝试其他方向。

1.4优缺点:

 1.4.1优点:

简单直观:算法的实现相对简单,使用递归的方式易于理解和编写代码。

空间效率:使用递归调用栈存储节点信息,通常比使用显式的栈更简洁,空间复杂度在大多数情况下相对较低。

找到一条路径即可:如果只需要找到一条可行路径,DFS 可能会比广度优先搜索(BFS)更快,因为它会沿着一条路径一直探索下去,直到找到终点。

1.4.2缺点:

不一定是最短路径:由于其深度优先的特性,找到的路径可能不是最短路径,而是先找到的一条可行路径。

可能会陷入死胡同:如果迷宫中存在大量死胡同,DFS 可能会陷入较深的路径,导致时间复杂度较高,在最坏情况下可能会遍历整个搜索空间。

1.5代码展示及其解释:

#include <iostream>
#include <vector>

using namespace std;

// 定义方向偏移量,上、右、下、左
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};

// 深度优先搜索函数
bool dfs(vector<vector<int>>& maze, vector<vector<bool>>& visited, int x, int y, int end_x, int end_y) {
    // 如果到达终点
    if (x == end_x && y == end_y) {
        return true;
    }
    visited[x][y] = true;
    for (int i = 0; i < 4; ++i) {
        int new_x = x + dx[i];
        int new_y = y + dy[i];
        // 检查是否越界、不是墙壁、未访问
        if (new_x >= 0 && new_x < maze.size() && new_y >= 0 && new_y < maze[0].size() && maze[new_x][new_y] == 0 &&!visited[new_x][new_y]) {
            if (dfs(maze, visited, new_x, new_y, end_x, end_y)) {
                return true;
            }
        }
    }
    visited[x][y] = false; // 回溯,标记为未访问
    return false;
}

int main() {
    int m = 5, n = 5;
    vector<vector<int>> maze = {{0, 1, 0, 0, 0},
                            {0, 0, 0, 1, 0},
                            {0, 1, 0, 1, 0},
                            {0, 1, 0, 0, 0},
                            {0, 0, 0, 0, 0}};
    vector<vector<bool>> visited(m, vector<bool>(n, false));
    int start_x = 0, start_y = 0;
    int end_x = 4, end_y = 4;
    if (dfs(maze, visited, start_x, start_y, end_x, end_y)) {
        cout << "Path found!" << endl;
    } else {
        cout << "No path found." << endl;
    }
    return 0;
}

 1·dfs 函数接收迷宫矩阵 maze、访问标记矩阵 visited 以及当前和终点的坐标。

2·首先检查是否到达终点,若到达则返回 true

3·标记当前节点已访问,尝试四个方向的新节点,若新节点满足条件且递归调用 dfs 找到路径,则返回 true

4·若都不满足,回溯并标记为未访问,返回 false 

 

那么下面我们就以一道洛谷的实题来切入解法分析解法,以及细节处理和易错点:

 二·走迷宫例题:

eefebebfafc7441e9bf7aa572d4fc1a1.png

测试用例: 

输入:

5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6

 输出:

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)

 

洛谷原题链接:走迷宫 - 洛谷

 三·分析操作:

首先当我们看到是“网格”,肯定就想到了,暴搜法(当然了也可以和决策树联系起来,但是画出来就太繁琐了,在心里知道即可);其次就是这个数据范围,也不是相对大:

d296505a7b9e459894228eb668818481.png

因此,可以考虑走一下暴搜;即从起点对应的坐标开始去:

2d11b567d13c4182b3b841e3e7fb2765.png 

 

这里就是细节:左上右下的顺序。 

这里我们题目给的位置坐标和我们dfs中用的不是一样的(dfs是数组中的下标;但是放入path中就是实际我们所说的;因此不要忘记加减1的操作)

然后去搜索;找到不是墙即1就把对应的坐标按照规则添加进去;之后以它为中心去左上右下调用dfs;一直进行下去;直到找到了终点就把它放入ret(我们这里是采用数组记录,最后打印)

当然了其实还是有一些细节处理:

细节处理:

①比如我们的标记数组:

这里如果我们按照是1就进入;明显是不合适的;因为可能已经走过了;之后又回来:

因此这里我们建议搞一个全局的bool数组标记走过的痕迹;或者在原数组操作:每当走过就把此位置标记成0;等回溯回来的时候在进行复原即可(本篇介绍的是原数组操作)。 

② 其次,因为我们输出打印的是按照规则的所有路径;这里我们需要记录:

eq?%281%2C1%29-%3E%282%2C1%29-%3E%282%2C2%29-%3E%282%2C3%29-%3E%283%2C3%29-%3E%284%2C3%29-%3E%284%2C4%29-%3E%284%2C5%29-%3E%285%2C5%29-%3E%285%2C6%29

这里博主是搞了个path记录当前走的路线然后当找到终点就把它存入ret中(这样是全局的,就免不了手动的进行回溯删除等操作了);当然了也可以搞成函数参数;然函数利用栈的性质自己解决(最后展示其他博主的写法);这里我们就先以全局path为准:

为了不让dfs函数看起来乱,因此博主另外封装了函数:

void add(string &path, int x, int y) {//符合情况添加到path后面
    path += "(";
    path += to_string(x);
    path += ",";
    path += to_string(y);
    path  += ")";
    path += "->";
}

比如这个函数就为了添加当前坐标; 但是如果我们的坐标如果是类似13这样的两位数呢(题目要求最大是两位数);因此转成string类型我们就要求一下长度,方便后序的删除操作了:

判断要删除多少个: 

int get_size(int x, int y) {//获得回溯时path要删除的字符长度
    return 5 + to_string(x).size() + to_string(y).size();
}//这里15to_stringsize是2;故这里要判断是一位数还是几位数

 回溯删除操作:

  int tmp2 = get_size(x+1,y+1);
  while (tmp2--)path.pop_back();

③有个我们很容易忽略的一点:

就是我们每次从起点进入dfs函数的时候需要把起点位置也标记上;后面防止重复走:

如果没有的话就直接35分啦:

393326ac69824daebe453ab46b207d65.png 

因此这一步是不可或缺的: 

 v[sx-1][sy-1]=0;

还有就是无路径就cout -1;也就对应如果我们的ret数组size为0的操作。 

 ④左上右下搜索:

这里我们可以直接搞四个dfs函数,传递不同参数;但是这样就看起来太繁琐了;因此我们可以用向量法,搞一个数组存放中心坐标对应的偏移量:

/向量数组:完成左上右下搜索:
int xx[4] = { 0,-1,0,1 };
int yy[4] = { -1,0,1,0 };

这样的话,我们根据对中心坐标进行偏移一个循环,一个dfs就搞定了 :

 for (int k = 0; k <= 3; k++) {//左上右下搜索
        int x = i + xx[k], y = j + yy[k];
        if (x >= 0 && x < m && y >= 0 && y < n && v[x][y] == 1) {
            v[x][y] = 0;//标记,防重
            add(path, x + 1, y + 1);
            dfs(v, x, y);
            //回溯:
            v[x][y] = 1;
            int tmp2 = get_size(x+1,y+1);
            while (tmp2--)path.pop_back();
        }

 四·代码展示:

#include<bits/stdc++.h>
using namespace std;
int m, n, sx, sy, tx, ty;//分别表示行数列数,起始坐标,终止坐标
//向量数组:完成左上右下搜索:
int xx[4] = { 0,-1,0,1 };
int yy[4] = { -1,0,1,0 };
string path;//记录每种答案
vector<string>ret;//答案数组
void add(string &path, int x, int y) {//符合情况添加到path后面
    path += "(";
    path += to_string(x);
    path += ",";
    path += to_string(y);
    path  += ")";
    path += "->";
}
int get_size(int x, int y) {//获得回溯时path要删除的字符长度
    return 5 + to_string(x).size() + to_string(y).size();
}//这里15to_stringsize是2;故这里要判断是一位数还是几位数
void dfs(vector<vector<int>>&v, int i, int j) {
    //递归出口;如果找到终止目标就放入ret,
    //但是此时如果进入这里path已经加入了终止坐标了
    if (i == tx - 1 && j == ty - 1) {
        //去除"->"
        path.pop_back();
        path.pop_back();
        ret.push_back(path);//放入ret
        path += "->";//复原,然后交给回溯操作完成删除
        return;
    }
    for (int k = 0; k <= 3; k++) {//左上右下搜索
        int x = i + xx[k], y = j + yy[k];
        if (x >= 0 && x < m && y >= 0 && y < n && v[x][y] == 1) {
            v[x][y] = 0;//标记,防重
            add(path, x + 1, y + 1);
            dfs(v, x, y);
            //回溯:
            v[x][y] = 1;
            int tmp2 = get_size(x+1,y+1);
            while (tmp2--)path.pop_back();
        }

    }

}
int main() {
    cin >> m >> n;
    vector<vector<int>>v(m, vector<int>(n));//不能全局:因为n,m未初始化
    //会崩;也可以是静态;但是注意大小范围即可
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cin >> v[i][j];
        }
    }
    cin >> sx >> sy >> tx >> ty;
    add(path, sx, sy);
    v[sx-1][sy-1]=0;//细节:起始坐标必须标记,因为这个坐标不会在dfs中标记
    dfs(v, sx - 1, sy - 1);
    if (ret.size()) for (int i = 0; i < ret.size(); i++) cout << ret[i] << endl;
    else cout << "-1" << endl;//无路径就-1
  
    return 0;
}

最后也是通过:

 496ecba162b74dbfa86be05c29ae4acc.png

其他类似解法: 

 上面我们不是说还可以把path搞成函数参数(利用函数特性完成自动回溯)以及不在原数组操作;搞了个bool数组来标记走过的路径:

那么它就来了:

#include<bits/stdc++.h>
using namespace std;
int a[17][17],s[17][17],n,m,bx,by,ex,ey;
const string c[16]={"0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
//c用来将整数下标对应字符串的转换 
bool flag;//标记是否输出过解 
void dfs(int bx,int by,string ans){
    if(bx==ex&&by==ey){cout<<ans<<endl;flag=1;}//输出解并标记有路可走 
    int d[4][2]={{0,-1},{-1,0},{0,1},{1,0}};//四个方向搜索 
    for(int i=0;i<4;i++){
        int x=bx+d[i][0],y=by+d[i][1];        
        if(a[x][y]==1&&s[x][y]==0){
            s[x][y]=s[bx][by]+1;//深搜 
            dfs(x,y,ans+"->"+"("+c[x]+","+c[y]+")");//将经历过的点串联起来 
            s[x][y]=0;//回溯 
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)cin>>a[i][j];
    cin>>bx>>by>>ex>>ey;s[bx][by]=1;    
    dfs(bx,by,"("+c[bx]+","+c[by]+")");//起点(bx,by) 
    if(!flag)cout<<-1<<endl;    
    return 0;
}

当到当前坐标,以它为中心去查询;如果发现合适(为1)那么就让原先路径加上对应规则的坐标然后传给下一层;这样每次回溯回来就不用手动删除了(函数的形参变化不影响实参) ;其次就是搞了个s的标记数组;保证了原数组的完整性。

五·本篇小结:

 本篇用我们熟悉的dfs去暴搜(当然数据肯定不能太大);其次就是我们设计dfs是如何的:

函数体(具体题目分析);返回类型一般根据是找所有情况(void)还是找一种即可(bool));标记数组防重复;如果原数组的值是特定的就可以对原数组操作,不需要外加全局bool数组),全局变量还是函数参数设计像整型实型等这样变量就需要传参即可类似路径数组这样就得全局);另外就是及时做好回溯和剪枝的处理。

 本篇分享结束了;欢迎大家多度支持呀!!!!

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962135.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQL进阶实战技巧:如何分析浏览到下单各步骤转化率及流失用户数?

目录 0 问题描述 1 数据准备 2 问题分析 3 问题拓展 3.1 跳出率计算 3.2 计算从浏览商品到支付订单的不同路径的用户数&#xff0c;并按照用户数降序排列。 往期精彩 0 问题描述 统计从浏览商品到最终下单的各个步骤的用户数和流失用户数,并计算转化率 用户表结构和…

Autosar-Os是怎么运行的?(内存保护)

写在前面&#xff1a; 入行一段时间了&#xff0c;基于个人理解整理一些东西&#xff0c;如有错误&#xff0c;欢迎各位大佬评论区指正&#xff01;&#xff01;&#xff01; 1.功能概述 以TC397芯片为例&#xff0c;英飞凌芯片集成了MPU模块&#xff0c; MPU模块采用了硬件机…

什么是Maxscript?为什么要学习Maxscript?

MAXScript是Autodesk 3ds Max的内置脚本语言,它是一种与3dsMax对话并使3dsMax执行某些操作的编程语言。它是一种脚本语言,这意味着您不需要编译代码即可运行。通过使用一系列基于文本的命令而不是使用UI操作,您可以完成许多使用UI操作无法完成的任务。 Maxscript是一种专有…

(一)QT的简介与环境配置WIN11

目录 一、QT的概述 二、QT的下载 三、简单编程 常用快捷键 一、QT的概述 简介 Qt&#xff08;发音&#xff1a;[kjuːt]&#xff0c;类似“cute”&#xff09;是一个跨平台的开发库&#xff0c;主要用于开发图形用户界面&#xff08;GUI&#xff09;应用程序&#xff0c;…

vim交换文件的作用

1.数据恢复&#xff1a;因为vim异常的退出&#xff0c;使用交换文件可以恢复之前的修改内容。 2.防止多人同时编辑&#xff1a;vim检测到交换文件的存在,会给出提示&#xff0c;以避免一个文件同时被多人编辑。 &#xff08;vim交换文件的工作原理&#xff1a;vim交换文件的工作…

SpringCloudGateWay和Sentinel结合做黑白名单来源控制

假设我们的分布式项目&#xff0c;admin是8087&#xff0c;gateway是8088&#xff0c;consumer是8086 我们一般的思路是我们的请求必须经过我们的网关8088然后网关转发到我们的分布式项目&#xff0c;那我要是没有处理我们绕过网关直接访问项目8087和8086不也是可以&#xff1…

将多目标贝叶斯优化与强化学习相结合用于TinyML

论文标题 Combining Multi-Objective Bayesian Optimization with Reinforcement Learning for TinyML 作者信息 Mark Deutel, Friedrich-Alexander-Universitt Erlangen-Nrnberg, Germany Georgios Kontes, Fraunhofer IIS, Fraunhofer Institute for Integrated Circuits …

Big Bird:适用于更长序列的Transformer模型

摘要 基于Transformer的模型&#xff0c;如BERT&#xff0c;已成为自然语言处理&#xff08;NLP&#xff09;中最成功的深度学习模型之一。然而&#xff0c;它们的一个核心限制是由于其全注意力机制&#xff0c;对序列长度的二次依赖&#xff08;主要是在内存方面&#xff09;…

26_DropDown使用方法

创建下拉框DropDown 其中样板Template 是展示的选项框 其中Caption 是选中某个选项之后 展示的内容&#xff08;Caption Text 说明文字/Caption Image 说明图示&#xff09; 修改其 说明文字Caption Text 创建一个说明图示Image 设置为居左 而Item是 展示的选项框所展示的文字与…

【redis进阶】redis 总结

目录 介绍一下什么是 Redis&#xff0c;有什么特点 Redis 支持哪些数据类型 Redis 数据类型底层的数据结构/编码方式是什么 ZSet 为什么使用跳表&#xff0c;而不是使用红黑树来实现 Redis 的常见应用场景有哪些 怎样测试 Redis 服务器的连通性 如何设置 key 的过期时间 Redis …

AI大模型开发原理篇-1:语言模型雏形之N-Gram模型

N-Gram模型概念 N-Gram模型是一种基于统计的语言模型&#xff0c;用于预测文本中某个词语的出现概率。它通过分析一个词语序列中前面N-1个词的出现频率来预测下一个词的出现。具体来说&#xff0c;N-Gram模型通过将文本切分为长度为N的词序列来进行建模。 注意&#xff1a;这…

Linux工具使用

1.gcc/g的使用 1.1程序翻译的过程 ①预处理&#xff1a;展开头文件&#xff0c;替换宏&#xff0c;调节编译&#xff0c;去注释。 ②编译&#xff1a;将代码变成汇编语言 ③汇编&#xff1a;将汇编代码变成二进制不可执行的目标文件。 ④链接&#xff1a;将多个我写的多个…

后端token校验流程

获取用户信息 前端中只有 await userStore.getInfo() 表示从后端获取数据 在页面中找到info对应的url地址&#xff0c;在IDEA中查找 这里是getInfo函数的声明&#xff0c;我们要找到这个函数的使用&#xff0c;所以点getInfo() Override public JSONObject getInfo() {JSO…

Python 梯度下降法(二):RMSProp Optimize

文章目录 Python 梯度下降法&#xff08;二&#xff09;&#xff1a;RMSProp Optimize一、数学原理1.1 介绍1.2 公式 二、代码实现2.1 函数代码2.2 总代码 三、代码优化3.1 存在问题3.2 收敛判断3.3 函数代码3.4 总代码 四、优缺点4.1 优点4.2 缺点 Python 梯度下降法&#xff…

excel如何查找一个表的数据在另外一个表是否存在

比如“Sheet1”有“张三”、“李四”“王五”三个人的数据&#xff0c;“Sheet2”只有“张三”、“李四”的数据。我们通过修改“Sheet1”的“民族”或者其他空的列&#xff0c;修改为“Sheet2”的某一列。这样修改后筛选这个修改的列为空的或者为出错的&#xff0c;就能找到两…

2024年数据记录

笔者注册时间超过98.06%的用户 CSDN 原力是衡量一个用户在 CSDN 的贡献和影响力的系统&#xff0c;笔者原力值超过99.99%的用户 其他年度数据

7层还是4层?网络模型又为什么要分层?

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 一、为什么要分层 \quad 网络通信的复杂性促使我们需要一种分层的方法来理解和管理网络。就像建筑一样&#xff0c;我们不会把所有功能都混在一起…

JxBrowser 8.2.2 版本发布啦!

JxBrowser 8.2.2 版本发布啦&#xff01; • 已更新 #Chromium 至更新版本 • 实施了多项质量改进 &#x1f517; 点击此处了解更多详情。 &#x1f193; 获取 30 天免费试用。

论文阅读(十五):DNA甲基化水平分析的潜变量模型

1.论文链接&#xff1a;Latent Variable Models for Analyzing DNA Methylation 摘要&#xff1a; 脱氧核糖核酸&#xff08;DNA&#xff09;甲基化与细胞分化密切相关。例如&#xff0c;已经观察到肿瘤细胞中的DNA甲基化编码关于肿瘤的表型信息。因此&#xff0c;通过研究DNA…

【综合决策模型】考虑生命周期评估LCA 与多目标优化MOO的综合决策模型MOOLCA

目录 1. 概念和目的1.1 生命周期评估 (LCA, Life Cycle Assessment)1.2 多目标优化 (MOO, Multi-Objective Optimization)1.3 MOOLCA 的目标2. MOOLCA 的组成2.1 生命周期评估模块2.2 优化模块2.3 决策支持模块参考Life Cycle Assessment with Multi-Objective Optimization (M…