【运筹优化】剩余空间法求解带顺序约束的二维矩形装箱问题 + Java代码实现
文章目录
- 一、带顺序约束的二维矩形装箱问题
- 二、剩余空间法
- 三、完整代码实现
- 3.1 Instance 实例类
- 3.2 Item 物品类
- 3.3 PlaceItem 已放置物品类
- 3.4 Solution 结果类
- 3.5 RSPackingWithWeight 剩余空间算法类
- 3.6 Run 运行类
- 3.7 测试案例
- 3.8 ReadDataUtil 数据读取类
- 3.9 运行结果展示
一、带顺序约束的二维矩形装箱问题
常规的二维矩形装箱问题只要求利用率尽可能大就可以了,但是在现实场景中,由于订单顺序等缘故,有一些物品需要优先于其他物品进行装载,这就诞生了本文要解决的“带顺序约束的二维矩形装箱问题”。
带顺序约束的二维矩形装箱问题给定每个物品一定的权重,要求按照权重从大到小的顺序进行装载。这个问题用天际线算法也能解决,但是效果很差,如下图所示:
所以就引出了本文的主角:剩余空间法。经过测试,剩余空间法的求解效果在带顺序约束的二维矩形装箱问题上可能优于天际线启发式算法。下面是剩余空间法排出的结果:
想了解天际线启发式的朋友可以参考:(【运筹优化】基于堆优化的天际线启发式算法和复杂的评分策略求解二维矩形装箱问题 + Java代码实现)
二、剩余空间法
剩余空间法思路很简单:每放入一个矩形,就把空间按照下图的方式切成两部分剩余空间。最开始,剩余空间就是整个容器。每次放置矩形找到最合适的剩余空间放就行了。
那么什么是最适合的剩余空间呢?这就涉及到评价规则了。
常见的评价规则有下面三种:
return itemW / remainingSpace.w; // 规则1:矩形宽度和剩余空间宽度越接近分越高
return itemH / remainingSpace.h; // 规则2:矩形高度和剩余空间高度越接近分越高
return (itemW*itemH) / (remainingSpace.w*remainingSpace.h); // 规则3:矩形面积和剩余空间面积越接近分越高
三、完整代码实现
3.1 Instance 实例类
public class Instance {// 边界的宽private double W;// 边界的高private double H;// 矩形列表private List<Item> itemList;// 是否允许矩形旋转private boolean isRotateEnable;public double getW() {return W;}public void setW(double w) {W = w;}public double getH() {return H;}public void setH(double h) {H = h;}public List<Item> getItemList() {return itemList;}public void setItemList(List<Item> itemList) {this.itemList = itemList;}public boolean isRotateEnable() {return isRotateEnable;}public void setRotateEnable(boolean rotateEnable) {isRotateEnable = rotateEnable;}
}
3.2 Item 物品类
public class Item {// 名字private String name;// 宽private double w;// 高private double h;// 权重private double weight;// 构造函数public Item(String name, double w, double h,double weight) {this.name = name;this.w = w;this.h = h;this.weight = weight;}// 复制单个Itempublic static Item copy(Item item) {return new Item(item.name, item.w, item.h,item.weight);}// 复制Item数组public static Item[] copy(Item[] items) {Item[] newItems = new Item[items.length];for (int i = 0; i < items.length; i++) {newItems[i] = copy(items[i]);}return newItems;}// 复制Item列表public static List<Item> copy(List<Item> items) {List<Item> newItems = new ArrayList<>();for (Item item : items) {newItems.add(copy(item));}return newItems;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getW() {return w;}public void setW(double w) {this.w = w;}public double getH() {return h;}public void setH(double h) {this.h = h;}public double getWeight() {return weight;}public void setWeight(double weight) {this.weight = weight;}
}
3.3 PlaceItem 已放置物品类
public class PlaceItem {// 名字private String name;// x坐标private double x;// y坐标private double y;// 宽(考虑旋转后的)private double w;// 高(考虑旋转后的)private double h;// 是否旋转private boolean isRotate;// 权重private double weight;// 构造函数public PlaceItem(String name, double x, double y, double w, double h, boolean isRotate,double weight) {this.name = name;this.x = x;this.y = y;this.w = w;this.h = h;this.isRotate = isRotate;this.weight = weight;}@Overridepublic String toString() {return "PlaceItem{" +"name='" + name + '\'' +", x=" + x +", y=" + y +", w=" + w +", h=" + h +", isRotate=" + isRotate +", weight=" + weight +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getX() {return x;}public void setX(double x) {this.x = x;}public double getY() {return y;}public void setY(double y) {this.y = y;}public double getW() {return w;}public void setW(double w) {this.w = w;}public double getH() {return h;}public void setH(double h) {this.h = h;}public boolean isRotate() {return isRotate;}public void setRotate(boolean rotate) {isRotate = rotate;}public double getWeight() {return weight;}public void setWeight(double weight) {this.weight = weight;}
}
3.4 Solution 结果类
public class Solution {// 已放置矩形private List<PlaceItem> placeItemList;// 放置总面积private double totalS;// 利用率private double rate;// 构造函数public Solution(List<PlaceItem> placeItemList, double totalS, double rate) {this.placeItemList = placeItemList;this.totalS = totalS;this.rate = rate;}public List<PlaceItem> getPlaceItemList() {return placeItemList;}public void setPlaceItemList(List<PlaceItem> placeItemList) {this.placeItemList = placeItemList;}public double getTotalS() {return totalS;}public void setTotalS(double totalS) {this.totalS = totalS;}public double getRate() {return rate;}public void setRate(double rate) {this.rate = rate;}
}
3.5 RSPackingWithWeight 剩余空间算法类
public class RSPackingWithWeight {// 边界的宽private double W;// 边界的高private double H;// 矩形数组private Item[] items;// 是否可以旋转private boolean isRotateEnable;/*** @param isRotateEnable 是否允许矩形旋转* @param W 边界宽度* @param H 边界高度* @param items 矩形集合* @Description 构造函数*/public RSPackingWithWeight(boolean isRotateEnable, double W, double H, Item[] items) {this.isRotateEnable = isRotateEnable;this.W = W;this.H = H;this.items = Item.copy(items);// 按权重排序Arrays.sort(this.items, new Comparator<Item>() {@Overridepublic int compare(Item o1, Item o2) {return -Double.compare(o1.getWeight(), o2.getWeight());}});}/*** @return 放置好的矩形列表* @Description 天际线启发式装箱主函数*/public Solution packing() {// 用来存储已经放置的矩形List<PlaceItem> placeItemList = new ArrayList<>();// 用来记录已经放置矩形的总面积double totalS = 0d;// 剩余空间列表 [x,y,w,h]List<RemainingSpace> remainingSpaceList = new ArrayList<>();// 初始剩余空间就是整个容器remainingSpaceList.add(new RemainingSpace(0, 0, W, H));// 按照顺序放置矩形for (int i = 0; i < items.length; i++) {double maxScore = -1;int bestRemainingSpaceIndex = -1;boolean bestRotate = false;// 找到第一个没有被放置的权重最大的矩形i// 遍历所有剩余空间(不旋转)for (int j = 0; j < remainingSpaceList.size(); j++) {double score = score(items[i].getW(), items[i].getH(), remainingSpaceList.get(j));if (compareDouble(maxScore, score) == -1) {maxScore = score;bestRemainingSpaceIndex = j;}}// 遍历所有剩余空间(旋转)if (isRotateEnable) {for (int j = 0; j < remainingSpaceList.size(); j++) {double score = score(items[i].getH(), items[i].getW(), remainingSpaceList.get(j));if (compareDouble(maxScore, score) == -1) {maxScore = score;bestRemainingSpaceIndex = j;bestRotate = true;}}}// 装载if (bestRemainingSpaceIndex >= 0) {RemainingSpace remainingSpace = remainingSpaceList.remove(bestRemainingSpaceIndex);PlaceItem placeItem;if (bestRotate) {// 旋转placeItem = new PlaceItem(items[i].getName(), remainingSpace.x, remainingSpace.y, items[i].getH(), items[i].getW(), true, items[i].getWeight());} else {// 不旋转placeItem = new PlaceItem(items[i].getName(), remainingSpace.x, remainingSpace.y, items[i].getW(), items[i].getH(), false, items[i].getWeight());}placeItemList.add(placeItem);totalS += (placeItem.getW() * placeItem.getH());remainingSpaceList.add(new RemainingSpace(remainingSpace.x, remainingSpace.y + placeItem.getH(), placeItem.getW(), remainingSpace.h - placeItem.getH()));remainingSpaceList.add(new RemainingSpace(remainingSpace.x + placeItem.getW(), remainingSpace.y, remainingSpace.w - placeItem.getW(), remainingSpace.h));}}// 输出for (int i = 0; i < placeItemList.size(); i++) {System.out.println("第" + (i + 1) + "个矩形为: " + placeItemList.get(i));}// 返回求解结果return new Solution(placeItemList, totalS, totalS / (W * H));}// 评分函数:评价矩形放在剩余空间里的分数private double score(double itemW, double itemH, RemainingSpace remainingSpace) {if (compareDouble(remainingSpace.w, itemW) == -1 || compareDouble(remainingSpace.h, itemH) == -1) {// 超出剩余空间,返回-1分return -1;}// 评分规则return itemW / remainingSpace.w; // 规则1:矩形宽度和剩余空间宽度越接近分越高
// return itemH / remainingSpace.h; // 规则2:矩形高度和剩余空间高度越接近分越高
// return (itemW*itemH) / (remainingSpace.w*remainingSpace.h); // 规则3:矩形面积和剩余空间面积越接近分越高}/*** @param d1 双精度浮点型变量1* @param d2 双精度浮点型变量2* @return 返回0代表两个数相等,返回1代表前者大于后者,返回-1代表前者小于后者,* @Description 判断两个双精度浮点型变量的大小关系*/private int compareDouble(double d1, double d2) {// 定义一个误差范围,如果两个数相差小于这个误差,则认为他们是相等的 1e-06 = 0.000001double error = 1e-06;if (Math.abs(d1 - d2) < error) {return 0;} else if (d1 < d2) {return -1;} else if (d1 > d2) {return 1;} else {throw new RuntimeException("d1 = " + d1 + " , d2 = " + d2);}}static class RemainingSpace {double x, y, w, h;public RemainingSpace(double x, double y, double w, double h) {this.x = x;this.y = y;this.w = w;this.h = h;}}}
3.6 Run 运行类
public class Run extends javafx.application.Application {private int counter = 0;@Overridepublic void start(Stage primaryStage) throws Exception {// 数据地址String path = "src/main/java/com/wskh/data/data_weight.txt";// 根据txt文件获取实例对象Instance instance = new ReadDataUtil().getInstance(path);// 记录算法开始时间long startTime = System.currentTimeMillis();// 实例化剩余空间法对象RSPackingWithWeight rsPackingWithWeight = new RSPackingWithWeight(instance.isRotateEnable(), instance.getW(), instance.getH(), instance.getItemList().toArray(new Item[0]));// 调用算法进行求解Solution solution = rsPackingWithWeight.packing();// 输出相关信息System.out.println("求解用时:" + (System.currentTimeMillis() - startTime) / 1000.0 + " s");System.out.println("共放置了矩形" + solution.getPlaceItemList().size() + "个");System.out.println("利用率为:" + solution.getRate());// 输出画图数据String[] strings1 = new String[solution.getPlaceItemList().size()];String[] strings2 = new String[solution.getPlaceItemList().size()];for (int i = 0; i < solution.getPlaceItemList().size(); i++) {PlaceItem placeItem = solution.getPlaceItemList().get(i);strings1[i] = "{x:" + placeItem.getX() + ",y:" + placeItem.getY() + ",l:" + placeItem.getH() + ",w:" + placeItem.getW() + "}";strings2[i] = placeItem.isRotate() ? "1" : "0";}System.out.println("data:" + Arrays.toString(strings1) + ",");System.out.println("isRotate:" + Arrays.toString(strings2) + ",");// --------------------------------- 后面这些都是画图相关的代码,可以不用管 ---------------------------------------------AnchorPane pane = new AnchorPane();Canvas canvas = new Canvas(instance.getW(), instance.getH());pane.getChildren().add(canvas);canvas.relocate(100, 100);// 绘制最外层的矩形canvas = draw(canvas, 0, 0, instance.getW(), instance.getH(), true);// 添加按钮Button nextButton = new Button("Next +1");Canvas finalCanvas = canvas;nextButton.setOnAction(new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent actionEvent) {try {PlaceItem placeItem = solution.getPlaceItemList().get(counter);draw(finalCanvas, placeItem.getX(), placeItem.getY(), placeItem.getW(), placeItem.getH(), false);counter++;} catch (Exception e) {Alert alert = new Alert(Alert.AlertType.WARNING);alert.setContentText("已经没有可以放置的矩形了!");alert.showAndWait();}}});//pane.getChildren().add(nextButton);primaryStage.setTitle("二维矩形装箱可视化");primaryStage.setScene(new Scene(pane, 1000, 1000, Color.AQUA));primaryStage.show();}private Canvas draw(Canvas canvas, double x, double y, double l, double w, boolean isBound) {GraphicsContext gc = canvas.getGraphicsContext2D();// 边框gc.setStroke(Color.BLACK);gc.setLineWidth(2);gc.strokeRect(x, y, l, w);// 填充if (!isBound) {gc.setFill(new Color(new Random().nextDouble(), new Random().nextDouble(), new Random().nextDouble(), new Random().nextDouble()));} else {gc.setFill(new Color(1, 1, 1, 1));}gc.fillRect(x, y, l, w);return canvas;}public static void main(String[] args) {launch(args);}}
3.7 测试案例
270,28,0,
1,82.3,10.4,0.54
2,123.5,20.62,0.25
3,80.4,16.2,0.42
4,74,13.41,0.81
5,105.6,11.6,0.19
6,62.1,10.1,0.67
7,43.2,8,0.93
8,39.8,11.25,0.73
9,50,12,0.3
10,75,8.6,0.89
11,129.92,16.24,0.08
12,90.8,14.9,0.16
3.8 ReadDataUtil 数据读取类
public class ReadDataUtil {public Instance getInstance(String path) throws IOException {BufferedReader bufferedReader = new BufferedReader(new FileReader(path));String input = null;Instance instance = new Instance();List<Item> itemList = new ArrayList<>();boolean isFirstLine = true;while ((input = bufferedReader.readLine()) != null) {String[] split = input.split(",");if (isFirstLine) {instance.setW(Double.parseDouble(split[0]));instance.setH(Double.parseDouble(split[1]));instance.setRotateEnable("1".equals(split[2]));isFirstLine = false;} else {itemList.add(new Item(split[0], Double.parseDouble(split[1]), Double.parseDouble(split[2]), Double.parseDouble(split[3])));}}instance.setItemList(itemList);return instance;}
}
3.9 运行结果展示
第1个矩形为: PlaceItem{name='7', x=0.0, y=0.0, w=43.2, h=8.0, isRotate=false, weight=0.93}
第2个矩形为: PlaceItem{name='10', x=43.2, y=0.0, w=75.0, h=8.6, isRotate=false, weight=0.89}
第3个矩形为: PlaceItem{name='4', x=43.2, y=8.6, w=74.0, h=13.41, isRotate=false, weight=0.81}
第4个矩形为: PlaceItem{name='8', x=0.0, y=8.0, w=39.8, h=11.25, isRotate=false, weight=0.73}
第5个矩形为: PlaceItem{name='6', x=118.2, y=0.0, w=62.1, h=10.1, isRotate=false, weight=0.67}
第6个矩形为: PlaceItem{name='1', x=180.3, y=0.0, w=82.3, h=10.4, isRotate=false, weight=0.54}
第7个矩形为: PlaceItem{name='3', x=180.3, y=10.4, w=80.4, h=16.2, isRotate=false, weight=0.42}
第8个矩形为: PlaceItem{name='9', x=118.2, y=10.1, w=50.0, h=12.0, isRotate=false, weight=0.3}
求解用时:0.002 s
共放置了矩形8个
利用率为:0.7693518518518518
data:[{x:0.0,y:0.0,l:8.0,w:43.2}, {x:43.2,y:0.0,l:8.6,w:75.0}, {x:43.2,y:8.6,l:13.41,w:74.0}, {x:0.0,y:8.0,l:11.25,w:39.8}, {x:118.2,y:0.0,l:10.1,w:62.1}, {x:180.3,y:0.0,l:10.4,w:82.3}, {x:180.3,y:10.4,l:16.2,w:80.4}, {x:118.2,y:10.1,l:12.0,w:50.0}],
isRotate:[0, 0, 0, 0, 0, 0, 0, 0],
相关文章:

【运筹优化】剩余空间法求解带顺序约束的二维矩形装箱问题 + Java代码实现
文章目录一、带顺序约束的二维矩形装箱问题二、剩余空间法三、完整代码实现3.1 Instance 实例类3.2 Item 物品类3.3 PlaceItem 已放置物品类3.4 Solution 结果类3.5 RSPackingWithWeight 剩余空间算法类3.6 Run 运行类3.7 测试案例3.8 ReadDataUtil 数据读取类3.9 运行结果展示…...

第四阶段15-关于权限,处理解析JWT时的异常,跨域请求,关于Spring Security的认证流程
处理解析JWT时的异常 由于解析JWT是在过滤器中执行的,而过滤器是整个服务器端中最早接收到所有请求的组件,此时,控制器等其它组件尚未运行,则不可以使用此前的“全局异常处理器”来处理解析JWT时的异常(全局异常处理器…...

毕业设计 基于51单片机的指纹红外密码电子锁
基于51单片机的指纹红外密码电子锁1、项目简介1.1 系统框架1.2 系统功能2、部分电路设计2.1 STC89C52单片机最小系统电路设计2.2 矩阵按键电路电路设计2.3 液晶显示模块电路设计3、部分代码展示3.1 LCD12864显示字符串3.2 串口初始化实物图1、项目简介 选题指导,项…...

【JavaWeb】数据链路层协议——以太网 + 应用层协议——DNS
以太网 以太网不是一个具体的网络,而是一个技术标准,主要应用于数据链路层和物理层。 以太网数据帧结构 以太网的数据帧结构由三部分构成: 帧头 载荷 帧尾 其中的MAC地址是六位,这样就比IPV4所表示的地址大很多,…...
docker 容器安装 python jre
Dockerfile FROM python:2.7.11-alpine RUN mkdir /usr/local/java WORKDIR /usr/local/java # 5.更改 Alpine 的软件源为阿里云,默认从官方源拉取比较慢 RUN echo http://mirrors.aliyun.com/alpine/v3.10/main/ > /etc/apk/repositories && \ echo…...
Linux下将C++程序打包成动态库静态库方法
之前在这篇文章里介绍过动态库和静态库的理论部分,这篇文章主要介绍下实际的操作步骤: 静态链接库生成 gcc -c main.cpp -o main.o ar -rc libmain.a main.o sudo cp libmain.a /usr/local/lib 调用即可解释一下上面的命令:前两步生成了libmain.a sudo…...

Centos7 服务器基线检查处理汇总
1、服务器超时设置 问题描叙 TMOUT的值大于key2且小于等于{key2}且小于等于key2且小于等于{key1}视为合规 查看命令:export检测结果 超时时间:0处理方式 备份/etc/profile文件 cp /etc/profile /etc/profile_bak编辑profile文件 vim /etc/profile修改/新增 TMO…...

PaddleOCR遇到 lanms-neo问题处理
在window环境中安装PaddleOCR依赖是真的蛋疼,关键官方论坛里也都没有具体的解决方案。吐槽。。。吐槽。。。 我在 “windows安装lanms-neo问题处理”文章中看到lanms-neo问题全过程解决。个人觉得文档说明不是很细致,导致我按步骤执行,还是安…...

coreldraw2023安装包下载及新功能介绍
对于广告标识业来说 coreldraw这个软件,对我们来说绝对不陌生,我从2008年开始接触到广告制作,到现在已经13多年了,从一开始的coreldraw 9红色的热气球开始。就被这个强大的软件所吸引,他有强大的排榜功能已经对位图的处…...

Nginx 负载均衡服务失败场景
nginx可以配置负载均衡,我们可以通过配置实现nginx负载均衡。这里部署了两个服务producter-one和producter-one2。 upstream proxyproducter-one {server producter-one:8080 weight1;server producter-one2:8080 weight1;}# 访问其他服务server {listen 9090…...

开学季哪个电容笔好?2023口碑最好电容笔推荐
虽说苹果原装的电容笔非常好用,性能也非常不错,但由于价格昂贵,普通的学生是没办法购买的,再加上重量比较大,使用时间长了,难免会让人感觉到疲劳。如果仅仅是为了学习记笔记,那就没必要再去购买…...
经验分享-如何使用http调用chatGPT-3.5-turbo模型API
今天上午,就在工作群里收到了关于openAI发布chatGPT官方模型的消息分享。openAI这次的动作真的很快啊,没想到这么快就直接发布了chatGPT目前所使用的模型api。据Open AI在官方消息,本次开放了ChatGPT和Whisper的模型API,可以供用户…...
【C#】yyyy-MM-dd HH:mm:ss 时间格式 时间戳 全面解读超详细
C# 日期转字符串 实例化一个时间字符串 DateTimeFormatInfo dfInfonew DateTimeFormatInfo(); dfInfo.ShortDatePattern "yyyy/MM/dd hh:mm:ss:ffff"; DateTime dt Convert.ToDateTime("2019/07/01 18:18:18:1818", dfInfo);日期转字符串 string dat…...

基于神经网络的滑模鲁棒控制
目录 前言 1.双关节机械手臂模型 2.神经网络自适应律设计 3. 滑模控制律设计 4. 仿真分析 4.1 仿真模型 4.2 仿真结果 4.3 小结 5 学习问题 前言 上一篇文章我介绍了神经网络补偿的机理,只不过控制律不同,本章我们结合滑模理论设计控制律&#…...

2023年融资融券研究报告
第一章 行业概况 融资融券是证券交易市场上的两种金融衍生品交易方式,主要用于股票、债券等证券的融资和投资。 融资是指投资者向证券公司借入资金购买证券,以期望股票价格上涨后卖出获得利润。融资需支付一定的利息和费用,利息根据借入的资…...

Nodejs环境配置 | Linux安装nvm | windows安装nvm
文章目录一. 前言二. Linux Nodejs环境配置1. 安装nvm2. 配置npm三. Windows Nodejs环境配置1. 安装nvm2. 配置npm四. nvm基本使用一. 前言 由于在实际开发中一些不同的项目需要不同的npm版本来启动,所以本篇文章会基于nvm这个node版本管理工具来进行Linux和Winodw…...

显示接口测试
背景需求两个显示器连接到一台PC,期望每台显示器可以单独显示,在一台显示器显示时,另外一台显示器同PC的连接断开,即系统下查看到连接状态为disconnected。同时在显示器上图形化显示当前显示器编号。如下图,期望当显示…...

Tcl_Init error: Can‘t find a usable init.tcl in the following directories
目录 问题 解决 小结 问题 最近在研究开源波形显示软件gtkwave时,Ubuntu18.04下编译打包完成,移植到另一个电脑上运行时,出现以下错误,如图: 擦掉的部分是一些路径信息,这个错误提示意味着您的系统中缺少所需的 Tcl 初始化文件,路径下确实没有init.tcl文…...

进程控制(详解)
进程控制上篇文章介绍了进程的相关概念,形如进程的内核数据结构task_struct 、进程是如何被操作系统管理的、进程的查看、进程标识符、进程状态、进程优先级、已经环境变量和进程地址空间等知识点; 本篇文章接着上篇文章继续对进程的控制进行展开&#x…...

瓜子大王稳住基本盘,洽洽食品做对了什么?
2月24日,洽洽食品披露2022年业绩快报,公司预计实现营收总收入68.82亿元,同比增长14.98%, 实现归母净利润9.77 亿元,同比增长5.21%,业绩基本符合市场预期。来源:洽洽食品2022年度业绩快报2022年,瓜子大王洽洽…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...