核心思路都是:需要一个安装在用户电脑上的“中间人”程序(本地客户端)来接管打印任务,然后通过某种通信方式命令这个客户端进行打印。

下面我将分平台详细阐述各种实现思路、优缺点和适用场景。

一、核心思路与公共组件:本地客户端

无论哪种方式,都需要一个部署在用户打印电脑上的本地程序。这个程序的核心职责是:

监听来自网络的打印命令。

获取打印数据和参数(如份数、双面打印等)。

调用系统打印接口,完成实际打印。

这个本地客户端通常可以用以下技术开发:

Electron (Node.js, 跨平台)

二、各平台调用方案

这是最主流和推荐的方案WebSocket,适用性最广,尤其是对于浏览器环境。

工作原理:

注册与连接:本地客户端启动后,向一个已知的服务器(或直接在本地)建立一个WebSocket连接或开始HTTP长轮询,并告知服务器“我在这台电脑上,准备好接收打印任务了”。通常需要客户端上报一个唯一标识(如MAC地址、登录用户名等)。

发送打印任务:APP、网页或小程序将打印数据(JSON、HTML、PDF文件流等)和打印机参数通过API发送到业务服务器。

服务器转发:业务服务器根据一定的路由规则(如:用户A的打印任务要发到他指定的电脑B),通过WebSocket或HTTP将任务推送给正在监听的目标客户端。

客户端执行打印:目标本地客户端收到任务后,解析数据,调用本地打印机驱动完成打印。

优点:

跨平台兼容:对APP、网页、小程序一视同仁,它们只与业务服务器交互,无需关心客户端具体实现。

穿透性强:只要能上网,无论APP/网页/小程序在哪里,都能将任务发送到指定地点的打印机。

集中管理:方便在服务端做任务队列、日志记录、权限控制等。

缺点:

依赖网络:必须保证本地客户端和业务服务器的网络连通性。

架构复杂:需要额外开发和维护一个业务服务器作为中转。

适用场景:

企业级应用、ERP、SaaS系统。

需要远程打印或打印任务需要集中管理的场景。

方案二:自定义URL协议 (PC端网页常用)
工作原理:

注册协议:在安装本地客户端时,在系统注册一个自定义URL协议(例如:diygwprint://)。

网页触发:在网页中通过JavaScript代码触发这个链接(如:window.location.href = 'diygwprint://print?data=...')。

客户端响应:系统会唤起注册了该协议的本地客户端,并将URL中的参数传递给它。

客户端处理:客户端解析URL参数(如base64编码的打印数据),执行打印。

优点:

简单直接:对于本地环境,实现起来非常快速。

无中间服务器:无需业务服务器中转,延迟低。

缺点:

仅限PC浏览器:APP和小程序无法直接使用此方式。

数据量限制:URL长度有限制,不适合传输大量数据(如图片、复杂的HTML)。

安全性:需要防范恶意网站随意调用。

体验问题:浏览器通常会弹出“是否允许打开此应用”的提示,体验不完美。

适用场景:

简单的PC端网页调用本地客户端场景,传输的数据量较小。

作为WebSocket方案的补充或备选方案。


四、打印数据格式建议
传递给本地客户端的数据最好结构化且通用:

JSON + 模板:发送JSON数据和模板名称,客户端根据模板渲染后打印。灵活且数据量小。

HTML:直接发送HTML字符串,客户端使用内置浏览器控件(如C#的WebBrowser)打印。开发简单,但样式控制可能不一致。

PDF:服务器端或前端生成PDF文件流/URL,客户端下载并打印。效果最精确,跨平台一致性最好,强烈推荐。

五、实战流程示例 (以最推荐的WebSocket方案为例)
开发本地客户端:

用Electron写一个Windows程序。

集成WebSocket客户端库,连接至业务服务器的WebSocket服务。

实现登录认证、心跳保持、接收打印指令({command: ‘print’, data: {...}, printer: ‘...’})。

接收到指令后,解析数据,调用System.Drawing.Printing命名空间下的类进行打印。

开发业务服务器:

提供WebSocket服务端。

提供RESTful API供APP/网页/小程序提交打印任务。

实现任务路由和转发逻辑。

const { ipcRenderer } = require('electron');class ElectronHistoryManager {constructor() {this.currentTab = 'history';this.currentPage = 1;this.pageSize = 20;this.totalPages = 1;this.allHistory = [];this.allQueue = [];this.filteredData = [];this.filters = {status: '',date: '',printer: '',search: ''};this.init();}async init() {await this.loadData();this.setupEventListeners();this.renderData();this.updateStats();}setupEventListeners() {// 搜索输入框事件document.getElementById('searchInput').addEventListener('input', (e) => {this.filters.search = e.target.value;this.applyFilters();});// 筛选器事件document.getElementById('statusFilter').addEventListener('change', (e) => {this.filters.status = e.target.value;this.applyFilters();});document.getElementById('dateFilter').addEventListener('change', (e) => {this.filters.date = e.target.value;this.applyFilters();});document.getElementById('printerFilter').addEventListener('change', (e) => {this.filters.printer = e.target.value;this.applyFilters();});// 模态框点击外部关闭document.getElementById('contentModal').addEventListener('click', (e) => {if (e.target.id === 'contentModal') {this.closeModal();}});}async loadData() {try {const result = await ipcRenderer.invoke('get-print-history');if (result.success) {this.allHistory = result.history || [];this.allQueue = result.queue || [];this.updatePrinterFilter();} else {console.error('获取打印历史失败:', result.error);this.showError('获取打印历史失败: ' + result.error);}} catch (error) {console.error('加载数据失败:', error);this.showError('加载数据失败: ' + error.message);}}updatePrinterFilter() {const printerSelect = document.getElementById('printerFilter');const allData = [...this.allHistory, ...this.allQueue];const printers = [...new Set(allData.map(job => job.printerName).filter(Boolean))];// 清空现有选项(保留"全部打印机")printerSelect.innerHTML = '<option value="">全部打印机</option>';// 添加打印机选项printers.forEach(printer => {const option = document.createElement('option');option.value = printer;option.textContent = printer;printerSelect.appendChild(option);});}updateStats() {const totalJobs = this.allHistory.length;const completedJobs = this.allHistory.filter(job => job.status === 'completed').length;const failedJobs = this.allHistory.filter(job => job.status === 'failed').length;const queueJobs = this.allQueue.length;document.getElementById('totalJobs').textContent = totalJobs;document.getElementById('completedJobs').textContent = completedJobs;document.getElementById('failedJobs').textContent = failedJobs;document.getElementById('queueJobs').textContent = queueJobs;}switchTab(tab) {this.currentTab = tab;this.currentPage = 1;// 更新标签样式document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));event.target.classList.add('active');// 显示对应内容document.getElementById('historyTab').style.display = tab === 'history' ? 'block' : 'none';document.getElementById('queueTab').style.display = tab === 'queue' ? 'block' : 'none';this.applyFilters();}applyFilters() {const sourceData = this.currentTab === 'history' ? this.allHistory : this.allQueue;this.filteredData = sourceData.filter(job => {// 文本搜索if (this.filters.search) {const searchTerm = this.filters.search.toLowerCase();const searchableText = [job.id || '',job.printerName || '',job.content || '',job.userId || '',job.status || ''].join(' ').toLowerCase();if (!searchableText.includes(searchTerm)) {return false;}}// 状态筛选if (this.filters.status && job.status !== this.filters.status) {return false;}// 日期筛选if (this.filters.date) {const jobDate = new Date(job.createdAt).toISOString().split('T')[0];if (jobDate !== this.filters.date) {return false;}}// 打印机筛选if (this.filters.printer && job.printerName !== this.filters.printer) {return false;}return true;});this.currentPage = 1;this.calculatePagination();this.renderData();}calculatePagination() {this.totalPages = Math.ceil(this.filteredData.length / this.pageSize);if (this.totalPages === 0) this.totalPages = 1;}renderData() {const loadingState = document.getElementById('loadingState');const emptyState = document.getElementById('emptyState');const pagination = document.getElementById('pagination');// 隐藏加载状态loadingState.style.display = 'none';if (this.filteredData.length === 0) {emptyState.style.display = 'block';pagination.style.display = 'none';return;}emptyState.style.display = 'none';// 计算当前页的数据const startIndex = (this.currentPage - 1) * this.pageSize;const endIndex = startIndex + this.pageSize;const pageData = this.filteredData.slice(startIndex, endIndex);// 渲染表格const tbody = this.currentTab === 'history' ? document.getElementById('historyTableBody') : document.getElementById('queueTableBody');tbody.innerHTML = '';pageData.forEach(job => {const row = this.createDataRow(job);tbody.appendChild(row);});// 更新分页this.updatePagination();pagination.style.display = 'flex';}createDataRow(job) {const row = document.createElement('tr');const formatDate = (dateString) => {const date = new Date(dateString);return date.toLocaleString('zh-CN');};const getStatusClass = (status) => {const statusMap = {'success': 'status-completed','completed': 'status-completed','error': 'status-failed','failed': 'status-failed','pending': 'status-pending','queued': 'status-pending','printing': 'status-printing','cancelled': 'status-cancelled'};return statusMap[status] || 'status-pending';};const getStatusText = (status) => {const statusMap = {'success': '已完成','completed': '已完成','error': '失败','failed': '失败','pending': '等待中','queued': '已加入队列','printing': '打印中','cancelled': '已取消'};return statusMap[status] || status;};if (this.currentTab === 'history') {row.innerHTML = `<td>${job.id}</td><td>${formatDate(job.createdAt)}</td><td>${job.printerName || '-'}</td><td><div class="content-preview" onclick="showContentDetail('${job.id}')" title="点击查看完整内容">${job.content ? job.content.substring(0, 50) + (job.content.length > 50 ? '...' : '') : '-'}</div></td><td><span class="status ${getStatusClass(job.status)}">${getStatusText(job.status)}</span>${job.error ? `<br><small style="color: #dc3545;">${job.error}</small>` : ''}</td><td>${job.copies || 1}</td><td>${job.userId || '-'}</td><td><div class="actions">${(job.status === 'completed' || job.status === 'success' || job.status === 'failed' || job.status === 'error' || job.status === 'cancelled') ? `<button class="btn btn-success btn-sm" onclick="reprintJob('${job.id}')">重打</button>` : ''}</div></td>`;} else {row.innerHTML = `<td>${job.id}</td><td>${formatDate(job.createdAt)}</td><td>${job.printerName || '-'}</td><td><div class="content-preview" onclick="showContentDetail('${job.id}')" title="点击查看完整内容">${job.content ? job.content.substring(0, 50) + (job.content.length > 50 ? '...' : '') : '-'}</div></td><td><span class="status ${getStatusClass(job.status)}">${getStatusText(job.status)}</span></td><td>${job.copies || 1}</td><td>${job.retryCount || 0}</td><td><div class="actions">${(job.status === 'pending' || job.status === 'queued' || job.status === 'printing') ? `<button class="btn btn-danger btn-sm" onclick="cancelJob('${job.id}')">取消</button>` : ''}</div></td>`;}return row;}updatePagination() {const pageInfo = document.getElementById('pageInfo');pageInfo.textContent = `第 ${this.currentPage} 页,共 ${this.totalPages} 页`;// 更新按钮状态const prevBtn = document.querySelector('.pagination button:first-child');const nextBtn = document.querySelector('.pagination button:last-child');prevBtn.disabled = this.currentPage === 1;nextBtn.disabled = this.currentPage === this.totalPages;}previousPage() {if (this.currentPage > 1) {this.currentPage--;this.renderData();}}nextPage() {if (this.currentPage < this.totalPages) {this.currentPage++;this.renderData();}}showContentDetail(jobId) {const allData = [...this.allHistory, ...this.allQueue];const job = allData.find(j => j.id === jobId);if (job && job.content) {document.getElementById('contentDetail').textContent = job.content;document.getElementById('contentModal').style.display = 'block';}}closeModal() {document.getElementById('contentModal').style.display = 'none';}async reprintJob(jobId) {const job = this.allHistory.find(j => j.id === jobId);if (!job) {this.showError('找不到指定的打印任务');return;}if (confirm(`确定要重新打印任务 ${jobId} 吗?`)) {try {const result = await ipcRenderer.invoke('reprint-job', {content: job.content,printerName: job.printerName,copies: job.copies,userId: job.userId,clientId: job.clientId});if (result.success) {this.showSuccess('重打任务已提交');await this.refreshData();} else {this.showError('重打任务提交失败: ' + result.error);}} catch (error) {console.error('重打任务失败:', error);this.showError('重打任务失败: ' + error.message);}}}async cancelJob(jobId) {if (confirm(`确定要取消打印任务 ${jobId} 吗?`)) {try {const result = await ipcRenderer.invoke('cancel-job', jobId);if (result.success) {this.showSuccess('打印任务已取消');await this.refreshData();} else {this.showError('取消打印任务失败: ' + result.error);}} catch (error) {console.error('取消打印任务失败:', error);this.showError('取消打印任务失败: ' + error.message);}}}async clearHistory() {if (confirm('确定要清除所有历史记录吗?此操作不可恢复。')) {try {const result = await ipcRenderer.invoke('clear-history');if (result.success) {this.showSuccess('历史记录已清除');await this.refreshData();} else {this.showError('清除历史记录失败: ' + result.error);}} catch (error) {console.error('清除历史记录失败:', error);this.showError('清除历史记录失败: ' + error.message);}}}clearFilters() {this.filters = {status: '',date: '',printer: '',search: ''};document.getElementById('searchInput').value = '';document.getElementById('statusFilter').value = '';document.getElementById('dateFilter').value = '';document.getElementById('printerFilter').value = '';this.applyFilters();}async refreshData() {document.getElementById('loadingState').style.display = 'block';document.getElementById('historyTab').style.display = 'none';document.getElementById('queueTab').style.display = 'none';document.getElementById('emptyState').style.display = 'none';await this.loadData();this.applyFilters();this.updateStats();// 恢复标签显示if (this.currentTab === 'history') {document.getElementById('historyTab').style.display = 'block';} else {document.getElementById('queueTab').style.display = 'block';}}showSuccess(message) {// 简单的成功提示const toast = document.createElement('div');toast.style.cssText = `position: fixed;top: 20px;right: 20px;background: #28a745;color: white;padding: 15px 20px;border-radius: 4px;z-index: 10000;box-shadow: 0 2px 10px rgba(0,0,0,0.2);`;toast.textContent = message;document.body.appendChild(toast);setTimeout(() => {document.body.removeChild(toast);}, 3000);}showError(message) {// 简单的错误提示const toast = document.createElement('div');toast.style.cssText = `position: fixed;top: 20px;right: 20px;background: #dc3545;color: white;padding: 15px 20px;border-radius: 4px;z-index: 10000;box-shadow: 0 2px 10px rgba(0,0,0,0.2);`;toast.textContent = message;document.body.appendChild(toast);setTimeout(() => {document.body.removeChild(toast);}, 5000);}
}// 全局函数
function switchTab(tab) {if (window.historyManager) {window.historyManager.switchTab(tab);}
}function applyFilters() {if (window.historyManager) {window.historyManager.applyFilters();}
}function clearFilters() {if (window.historyManager) {window.historyManager.clearFilters();}
}function refreshData() {if (window.historyManager) {window.historyManager.refreshData();}
}function clearHistory() {if (window.historyManager) {window.historyManager.clearHistory();}
}function previousPage() {if (window.historyManager) {window.historyManager.previousPage();}
}function nextPage() {if (window.historyManager) {window.historyManager.nextPage();}
}function reprintJob(jobId) {if (window.historyManager) {window.historyManager.reprintJob(jobId);}
}function cancelJob(jobId) {if (window.historyManager) {window.historyManager.cancelJob(jobId);}
}function showContentDetail(jobId) {if (window.historyManager) {window.historyManager.showContentDetail(jobId);}
}function closeModal() {if (window.historyManager) {window.historyManager.closeModal();}
}// 标题栏控制功能
let isMaximized = false;function minimizeWindow() {ipcRenderer.send('history-window-minimize');
}function toggleMaximize() {ipcRenderer.send('history-window-toggle-maximize');
}function closeWindow() {ipcRenderer.send('history-window-close');
}// 监听窗口状态变化
ipcRenderer.on('window-maximized', () => {isMaximized = true;updateTitlebarDrag();
});ipcRenderer.on('window-unmaximized', () => {isMaximized = false;updateTitlebarDrag();
});// 更新标题栏拖动状态
function updateTitlebarDrag() {const titlebar = document.querySelector('.custom-titlebar');if (titlebar) {titlebar.style.webkitAppRegion = isMaximized ? 'no-drag' : 'drag';}
}// 创建全局实例
document.addEventListener('DOMContentLoaded', () => {window.historyManager = new ElectronHistoryManager();// 设置标题栏双击事件const titlebar = document.querySelector('.custom-titlebar');if (titlebar) {titlebar.addEventListener('dblclick', (e) => {// 排除控制按钮区域if (!e.target.closest('.titlebar-controls')) {toggleMaximize();}});}
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/96657.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/96657.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/96657.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java集合(Collection、Map、转换)

✅ 推荐使用 ❌ 已过时 1. Collection Collection 是集合框架的根接口之一&#xff0c;它是所有单列集合&#xff08;如 List、Set、Queue 等&#xff09;的公共父接口。Collection 接口定义了集合的基本操作&#xff0c;比如添加、删除、遍历等。 Collection ├── List │ …

全国网络安全知识竞赛有哪些

全国范围内有多种类型的网络安全知识竞赛&#xff0c;涵盖国家级、行业级、高校、青少年和企业等多个维度。以下是主要的网络安全知识竞赛分类及详细介绍&#xff1a;一、国家级网络安全竞赛"强网杯"全国网络安全挑战赛主办单位&#xff1a;中央网信办、河南省人民政…

系统架构设计师备考第1天——系统架构概述

一、架构本质与角色定位架构 系统的骨架 ✅ 核心作用&#xff1a; 决定系统的健壮性、生命周期、扩展性衔接需求与实现&#xff0c;保障早期质量 &#x1f468;&#x1f4bb; 架构师核心能力&#xff1a;能力维度具体要求技术掌控力精通基础技术&#xff0c;洞悉局部瓶颈决策设…

c#实现鼠标mousemove事件抽稀,避免大数据阻塞网络

这个封装类可以独立于具体的网络传输逻辑&#xff0c;为任何需要减少鼠标移动数据量的应用提供灵敏度和数据量优化。 核心优化功能 1. 灵敏度调整 // 减少微小移动的数据发送 (2, 1) 0.5 → (1, 0) // 忽略微小移动2. 移动累积 // 累积多次小移动&#xff0c;批量发送 (1, 0) …

机器学习 [白板推导](十三)[条件随机场]

​ 17. 条件随机场&#xff08;Conditional Random Field&#xff0c;CRF&#xff09; 17.1. 背景 机器学习分类模型中&#xff0c;有硬分类和软分类两种主流思想&#xff0c;其中硬分类模型有支持向量机SVM&#xff08;最大化几何间隔&#xff09;、感知机PLA&#xff08;误…

调味品生产过程优化中Ethernet/IP转ProfiNet协议下施耐德 PLC 与欧姆龙 PLC 的关键通信协同案例

案例背景在食品饮料行业&#xff0c;生产过程的精准控制对于保证产品质量和安全至关重要。某知名食品饮料企业的生产线上&#xff0c;前处理、灌装和包装环节采用了基于 ProfiNet 主站的施耐德 M340 系列 PLC 进行控制&#xff0c;以确保生产过程的稳定性和精确性。而原料仓储和…

Elasticsearch vs 单表LIKE查询性能对比

关键因素影响 1、索引结构&#xff1a; .Elasticsearch使用倒排索引&#xff0c;特别适合文本搜索 .传统数据库即使有索引&#xff0c;对LIKE %keyword%这种模式也无法有效利用 2、查询复杂度&#xff1a; .简单查询&#xff1a;ES快5-10倍 .复杂组合查询&#xff1a;ES可能快1…

如何通过WordPress联盟营销获取潜在客户

您是否经营着一个销售周期较长的业务&#xff1f; 那么你就会知道&#xff0c;从首次访问者那里获得立即销售的机会是很少见的。 当然&#xff0c;您的潜在客户在进行重大投资之前需要时间进行研究、比较各种方案并建立信任。这时&#xff0c;联盟营销线索挖掘就成为您的秘密…

git实战(8)git高阶命令分析【结合使用场景】

以下是 Git 高阶命令分享&#xff0c;涵盖高效协作、历史重构、问题排查等场景&#xff0c;助你成为 Git 高手&#xff1a; 一、历史重构与清理 1. 交互式变基&#xff08;改写历史&#xff09; git rebase -i HEAD~3 # 修改最近3次提交操作选项&#xff1a; reword&#xff1…

生成一个竖直放置的div,宽度是350px,上面是标题固定高度50px,下面是自适应高度的div,且有滚动条

<!-- 我要生成一个竖直放置的div&#xff0c;宽度是350px&#xff0c;上面是标题固定高度50px&#xff0c;下面是自适应高度的div&#xff0c;且有滚动条。 --><style>html,body{/* height:100vh; */margin:10px; padding:10px;} </style><div style"…

题解:P13754 【MX-X17-T3】Distraction_逆序对_前缀和_Ad-hoc_算法竞赛C++

Beginning 这道题思维难度很大&#xff0c;有两个难点其实都不好解决&#xff0c;但因为其代码太过弱智所以只是绿题。 本题解详细地分析了做题时的历程与思路&#xff0c;所以希望大家可以仔细地完整阅读。 Analysis 首先先大体观察一下题目的性质&#xff1a;nnn 是排列&…

Android Studio下载gradle文件很慢的捷径之路

小伙伴们是不是也经常遇到导入新的项目时&#xff0c;AS一直卡在gradle的下载中。下面介绍一种简单暴力的方式来处理这个问题。 首先我们到gradle的官网下载自己想要的gradle版本。我这里以gradle7.5为例。点击下载gradle-7.5-bin.zip的压缩包。下载完成后无需解压。直接到C:\U…

【C++】全局变量/静态变量的初始化时机

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录一、全局变量下断点调试1. int a 10; —— 不能卡住断点2. static int b; —— 不能卡住断点3. MyClass c; —— 可以卡住断点4. static MyClass d; —— 可以卡住断…

水体反光 + 遮挡难题破解!陌讯多模态融合算法在智慧水务的实测优化

一、智慧水务行业检测痛点&#xff08;数据支撑 场景难点&#xff09; 根据《2023 年中国智慧水务发展报告》&#xff0c;当前水务监控系统在核心业务场景中面临两大效率瓶颈&#xff0c;直接影响水厂运维与供水安全&#xff1a; 高误报率导致运维资源浪费&#xff1a;水厂沉…

C++的指针和引用:

目录 引用&#xff1a; 注意&#xff1a; 左值引用和右值引用&#xff1a; 左值引用&#xff1a; 右值引用&#xff1a; 指针&#xff1a; 指针与引用的区别&#xff1a; 引用&#xff1a; 在C中&#xff0c;‌引用‌是一种为已存在变量创建别名的机制&#xff0c;它允…

图像处理中的伪影

目录 一、块效应伪影 / 块状伪影 二、 去除块状伪影 三、振铃伪影 一、块效应伪影 / 块状伪影 块状伪影(Blocking Artefacts)是对经过变换编码的图像进行重建时&#xff0c;图像中可能会出现压缩过程产生的可见伪影。基于块的变换编码中&#xff0c;一种常见伪影是 “块效应…

Java:对象的浅拷贝与深拷贝

目录 一、概念 二、实现方式 2.1 浅拷贝&#xff08;不推荐&#xff09; 2.2 深拷贝 2.2.1 方法一&#xff1a;重写 clone() 方法并递归克隆&#xff08;常用&#xff09; 2.2.2 方法二&#xff1a;通过序列化实现&#xff08;更强大&#xff0c;但更重&#xff09; 2.2…

佰钧成 社招 一面

1. “评估需求、排期”的工作流程&#xff1f; “我的工作流程一般是这样的&#xff1a; 需求评审&#xff1a; 首先会和产品、后端同学一起过需求&#xff0c;确保我完全理解了业务背景和要实现的价值&#xff0c;而不仅仅是功能点。技术方案设计&#xff1a; 之后&#xff0c…

最短路径问题(图论)

1 Floyd 作用&#xff1a; 求图中所有顶点之间的最短路径&#xff0c;包括有向图或者无向图&#xff0c;权重正负皆可&#xff0c;用来一次性求所有点之间的最短路径。 思路是 通过逐步扩大中间层&#xff0c;使得最短路径不断被更新&#xff0c;直到中间层扩大到n位置&#…

2025年8月新算法—云漂移优化算法(Cloud Drift Optimization Algorithm, CDO)

1、简介 这项研究介绍了云漂移优化&#xff08;数位长&#xff09;算法&#xff0c;这是一种创新的自然启发的元启发式方法来解决复杂的优化问题。CDO模仿受大气力影响的云粒子的动态行为&#xff0c;在探索和利用之间取得了微妙的平衡。它具有自适应权重调整机制&#xff0c;可…