基于 C++ 实现的智能物流配送系统模拟程序
一、项目简介
本项目是一个基于C++实现的智能物流配送系统模拟程序,综合运用了多种经典算法,用于完成以下核心任务:
- 📍路径规划(最短路径、配送路线优化)
- 🚚车辆调度(容量 + 时间窗约束)
- 📦库存优化(预算约束下的补货决策)
- 🔍算法对比演示(贪心 / 2-opt / 回溯 + 分支限界)
系统支持文件数据输入 + 自动示例数据生成 + 菜单式交互操作
二、系统功能概览
1️⃣ 用户登录模块
- 默认账号:
1 - 默认密码:
123456 - 最多 3 次登录尝试
2️⃣ 基础数据管理
系统自动加载或生成以下数据文件:
| 文件名 | 内容 |
|---|---|
nodes.txt | 节点信息(含仓库) |
edges.txt | 路网边及距离 |
orders.txt | 客户订单 |
vehicles.txt | 车辆信息 |
inventory.txt | 库存与补货方案 |
若文件不存在,程序会自动生成示例数据,确保可直接运行。
3️⃣ 路径规划(Dijkstra)
- 支持任意两节点之间的最短路径查询
- 输出:
- 最短距离
- 具体路径节点序列
📌 使用算法:
- Dijkstra 单源最短路径算法
- 基于邻接表 + 优先队列实现
4️⃣ 车辆调度(带时间窗)
调度目标
在满足以下约束的前提下,尽可能分配订单:
- 🚚 车辆容量约束
- ⏱ 订单时间窗(readyTime / dueTime)
调度策略
- 订单按最早截止时间优先
- 对每个订单选择最早可完成的可行车辆
- 若无车辆满足,则标记为未分配订单
📌 算法类型:
- 贪心调度算法(启发式)
5️⃣ 路线规划与优化
① 初始路线生成
- 基于最短路距离矩阵
- 使用最近邻贪心算法(Nearest Neighbor)
- 路线形式:
仓库 → 客户1 → 客户2 → ... → 仓库
② 小规模精确优化(≤10 个客户)
- 回溯 + 分支限界(TSP 变体)
- 自动以贪心解作为上界进行剪枝
- 输出:
- 贪心距离
- 最优距离
- 搜索节点数
- 剪枝次数
- 优化率
③ 大规模近似优化
- 使用2-opt 局部搜索算法
- 对初始路线进行边交换优化
📌 涉及算法:
- 贪心
- 回溯 + 分支限界
- 2-opt 局部优化
6️⃣ 库存优化(动态规划)
问题描述
在给定总预算 B的条件下,为每种商品选择:
- 不补货
- 或选择一种补货方案
目标是:
最小化缺货罚金(等价于最大化需求满足度)
模型说明
- 缺货量 =
max(0, demand - (onHand + 补货量)) - 罚金 =
缺货量 × unitPenalty
📌 算法类型:
- 多物品 + 多方案 + 预算约束的动态规划
- 状态:
DP[i][b]
表示前i个物品、预算b下的最小罚金
输出内容
- 最优使用预算
- 每个物品的补货决策
- 缺货情况与罚金统计
三、菜单功能说明
============================= 智能物流配送系统 ============================= 1. 查看基础数据 2. 路径规划:两点最短路径(Dijkstra) 3. 配送规划(时间窗调度 + 路线优化) 4. 路线优化对比演示(贪心 vs 2-opt) 5. 库存优化(动态规划 DP) 6. 退出系统四、数据文件格式说明
📄 nodes.txt
nodeId nodeName示例:
0Depot1A2B3C4D5E6F7G8H9I10J11K12L📄 edges.txt
u v weight示例:
01402303612214723425636545347856458669778571098939116101141012711125📄 orders.txt
orderId nodeId demand serviceTime readyTime dueTime示例:
100132015101243018102322525103454322104522030105632102810674362010782101210893282610910541235110112101011112431540📄 vehicles.txt
vehId capacity startTime示例:
1100280360📄 inventory.txt
itemName onHand demand unitPenalty optionCount qty1 cost1 qty2 cost2 ...示例:
Widget21583366101218Gadget512632447813Bolt203532103205Nut102543551092015Screw5080222064010五、编译与运行方式
💻 编译(Linux / macOS / Windows MinGW)
g++ -std=c++17 main.cpp -o logistics▶ 运行
./logisticsWindows(CMD / PowerShell):
logistics.exe六、特色与加分点
✅ 多算法综合应用(贪心 / Dijkstra / DP / 回溯)
✅ 支持时间窗约束的车辆调度
✅ 路线优化算法对比与性能统计
✅ 自动示例数据生成,开箱即用
✅ 菜单式交互,演示友好
✅ 代码结构清晰,适合课程答辩讲解
七.项目源码
#include<bits/stdc++.h>usingnamespacestd;/* ========================================================= 智能物流配送系统 - 路径规划:Dijkstra(最短路) - 车辆调度:贪心(需求降序 + 可用车辆优先 + 容量约束) - 库存优化:动态规划(多物品多补货方案 + 预算约束最小成本/最大满足) - 可选:回溯+分支限界(小规模路线精确优化) ========================================================= 文件数据(自动生成示例): nodes.txt : 节点列表(id name) edges.txt : 边(u v w) orders.txt : 订单(orderId nodeId demand serviceTime) vehicles.txt : 车辆(vehId capacity startTime) inventory.txt : 库存(itemName onHand demand unitPenalty optionCount [qty cost]...) ========================================================= */staticconststring kAccount="1";staticconststring kPassword="123456";// ---------- 回溯统计(用于展示分支限界效果) ----------staticlonglongg_dfsCount=0;staticlonglongg_pruneCount=0;// ---------- 平台清屏/暂停 ----------staticvoidcls(){#ifdef_WIN32system("cls");#elsecout<<"\033[2J\033[H";#endif}staticvoidpauseAny(){#ifdef_WIN32system("pause");#elsecout<<"按回车继续...";cin.ignore(numeric_limits<streamsize>::max(),'\n');cin.get();#endif}// ---------- 数据结构 ----------structNode{intid{};string name;};structEdge{intto{};intw{};};structOrder{intorderId{};intnodeId{};intdemand{};intserviceTime{};intreadyTime{};// 最早可服务时间intdueTime{};// 最晚完成时间};structVehicle{intvehId{};intcapacity{};intstartTime{};// 可用时间(例如 0 表示立即)};structRoutePlan{intvehId{};vector<int>orderIds;// 分配到该车辆的订单IDvector<int>visitNodes;// 实际访问节点序列(含仓库0)inttotalDemand{};intfinishTime{};inttotalDistance{};};structInventoryOption{intqty{};intcost{};};structInventoryItem{string name;intonHand{};intdemand{};intunitPenalty{};// 缺货单位罚金(越大越希望满足)vector<InventoryOption>options;// 补货方案:补qty 花cost};structGraph{vector<Node>nodes;vector<vector<Edge>>adj;unordered_map<int,int>id2idx;// nodeId -> index in nodes};// ---------- 工具:文件存在 ----------staticboolfileExists(conststring&path){ifstreamin(path);return(bool)in;}// ---------- 示例数据生成 ----------staticvoidwriteSampleDataIfMissing(){if(!fileExists("nodes.txt")){ofstreamout("nodes.txt");// 0 号默认仓库out<<"0 Depot\n";out<<"1 A\n";out<<"2 B\n";out<<"3 C\n";out<<"4 D\n";out<<"5 E\n";}if(!fileExists("edges.txt")){ofstreamout("edges.txt");// 无向图边:u v wout<<"0 1 4\n";out<<"0 2 2\n";out<<"1 2 1\n";out<<"1 3 5\n";out<<"2 3 8\n";out<<"2 4 10\n";out<<"3 4 2\n";out<<"3 5 6\n";out<<"4 5 3\n";}if(!fileExists("orders.txt")){ofstreamout("orders.txt");// orderId nodeId demand serviceTimeout<<"100 1 3 2\n";out<<"101 2 4 3\n";out<<"102 3 2 2\n";out<<"103 4 5 4\n";out<<"104 5 2 2\n";}if(!fileExists("vehicles.txt")){ofstreamout("vehicles.txt");// vehId capacity startTimeout<<"1 8 0\n";out<<"2 7 0\n";}if(!fileExists("inventory.txt")){ofstreamout("inventory.txt");/* itemName onHand demand unitPenalty optionCount [qty cost]... 例如:ItemX 2 8 10 3 (3,8) (5,13) (8,20) */out<<"Widget 2 10 8 3 3 6 6 10 10 16\n";out<<"Gadget 5 9 6 3 2 4 4 7 6 10\n";out<<"Bolt 20 30 3 2 10 3 20 5\n";}}// ---------- 读取数据 ----------staticGraphloadGraph(){Graph g;ifstreamnIn("nodes.txt");if(!nIn)throwruntime_error("无法打开 nodes.txt");g.nodes.clear();intid;string name;while(nIn>>id>>name){g.nodes.push_back({id,name});}g.adj.assign(g.nodes.size(),{});for(inti=0;i<(int)g.nodes.size();i++){g.id2idx[g.nodes[i].id]=i;}ifstreameIn("edges.txt");if(!eIn)throwruntime_error("无法打开 edges.txt");intu,v,w;while(eIn>>u>>v>>w){if(!g.id2idx.count(u)||!g.id2idx.count(v))continue;intui=g.id2idx[u],vi=g.id2idx[v];g.adj[ui].push_back({vi,w});g.adj[vi].push_back({ui,w});}returng;}staticvector<Order>loadOrders(){ifstreamin("orders.txt");if(!in)throwruntime_error("无法打开 orders.txt");vector<Order>orders;Order o;while(in>>o.orderId>>o.nodeId>>o.demand>>o.serviceTime>>o.readyTime>>o.dueTime){orders.push_back(o);}returnorders;}staticvector<Vehicle>loadVehicles(){ifstreamin("vehicles.txt");if(!in)throwruntime_error("无法打开 vehicles.txt");vector<Vehicle>vs;Vehicle v;while(in>>v.vehId>>v.capacity>>v.startTime){vs.push_back(v);}returnvs;}staticvector<InventoryItem>loadInventory(){ifstreamin("inventory.txt");if(!in)throwruntime_error("无法打开 inventory.txt");vector<InventoryItem>items;while(true){InventoryItem it;intoptionCount;if(!(in>>it.name>>it.onHand>>it.demand>>it.unitPenalty>>optionCount))break;it.options.clear();for(inti=0;i<optionCount;i++){InventoryOption op;in>>op.qty>>op.cost;it.options.push_back(op);}items.push_back(it);}returnitems;}// ---------- 路径规划:Dijkstra 最短路 ----------staticpair<vector<int>,vector<int>>dijkstra(constGraph&g,intsrcNodeId){intn=(int)g.nodes.size();constintINF=1e9;vector<int>dist(n,INF),parent(n,-1);if(!g.id2idx.count(srcNodeId))throwruntime_error("srcNodeId 不存在");ints=g.id2idx.at(srcNodeId);usingP=pair<int,int>;// dist, idxpriority_queue<P,vector<P>,greater<P>>pq;dist[s]=0;pq.push({0,s});while(!pq.empty()){auto[d,u]=pq.top();pq.pop();if(d!=dist[u])continue;for(autoe:g.adj[u]){if(dist[e.to]>dist[u]+e.w){dist[e.to]=dist[u]+e.w;parent[e.to]=u;pq.push({dist[e.to],e.to});}}}return{dist,parent};}staticvector<int>restorePathByIdx(constvector<int>&parent,intsrcIdx,intdstIdx){vector<int>path;intcur=dstIdx;while(cur!=-1){path.push_back(cur);if(cur==srcIdx)break;cur=parent[cur];}reverse(path.begin(),path.end());if(path.empty()||path.front()!=srcIdx)return{};returnpath;}// ---------- 车辆调度:贪心分配订单到车辆 ----------// 策略:订单按 demand 降序(First-Fit Decreasing),车辆按“最早可用时间/剩余容量”选择staticvector<RoutePlan>scheduleVehiclesWithTimeWindow(constvector<Order>&orders,constvector<Vehicle>&vehicles){// 按 dueTime(最紧急)优先vector<Order>ord=orders;sort(ord.begin(),ord.end(),[](constOrder&a,constOrder&b){returna.dueTime<b.dueTime;});structVehState{Vehicle v;intremainingCap;intcurrentTime;vector<int>assignedOrderIds;inttotalDemand;};vector<VehState>states;for(auto&v:vehicles){states.push_back({v,v.capacity,v.startTime,{},0});}vector<int>unassigned;for(auto&o:ord){intbest=-1;intbestFinish=INT_MAX;for(inti=0;i<(int)states.size();i++){if(states[i].remainingCap<o.demand)continue;intarrival=max(states[i].currentTime,o.readyTime);intfinish=arrival+o.serviceTime;if(finish<=o.dueTime){if(finish<bestFinish){bestFinish=finish;best=i;}}}if(best==-1){unassigned.push_back(o.orderId);continue;}states[best].assignedOrderIds.push_back(o.orderId);states[best].remainingCap-=o.demand;states[best].currentTime=bestFinish;states[best].totalDemand+=o.demand;}vector<RoutePlan>plans;for(auto&st:states){RoutePlan rp;rp.vehId=st.v.vehId;rp.orderIds=st.assignedOrderIds;rp.totalDemand=st.totalDemand;rp.finishTime=st.currentTime;plans.push_back(rp);}if(!unassigned.empty()){cout<<"\n? 未分配订单(时间窗/容量限制):";for(intid:unassigned)cout<<id<<" ";cout<<"\n";}returnplans;}// ---------- 路线生成:贪心最近邻(基于最短路距离矩阵) ----------staticvector<vector<int>>allPairsShortestPathDist(constGraph&g){intn=(int)g.nodes.size();vector<vector<int>>dist(n,vector<int>(n,(int)1e9));for(inti=0;i<n;i++){auto[d,p]=dijkstra(g,g.nodes[i].id);for(intj=0;j<n;j++)dist[i][j]=d[j];}returndist;}staticvector<int>buildRouteNearestNeighbor(constGraph&g,constvector<vector<int>>&distMat,intdepotId,constvector<int>&customerNodeIds){if(!g.id2idx.count(depotId))throwruntime_error("depotId 不存在");intdepotIdx=g.id2idx.at(depotId);vector<int>targets;for(intnid:customerNodeIds){if(g.id2idx.count(nid))targets.push_back(g.id2idx.at(nid));}sort(targets.begin(),targets.end());targets.erase(unique(targets.begin(),targets.end()),targets.end());vector<int>routeIdx;routeIdx.push_back(depotIdx);vector<int>unvisited=targets;intcur=depotIdx;while(!unvisited.empty()){intbestPos=0;for(inti=1;i<(int)unvisited.size();i++){if(distMat[cur][unvisited[i]]<distMat[cur][unvisited[bestPos]]){bestPos=i;}}intnxt=unvisited[bestPos];routeIdx.push_back(nxt);cur=nxt;unvisited.erase(unvisited.begin()+bestPos);}// 回仓库routeIdx.push_back(depotIdx);// 转成 nodeIdvector<int>routeNodeId;for(intidx:routeIdx)routeNodeId.push_back(g.nodes[idx].id);returnrouteNodeId;}// ---------- 回溯 + 分支限界:小规模精确路线(可选) ----------// 对每辆车的客户点 <= 10 时,尝试找更优的闭环路径(TSP 变体)// 使用 distMat,进行回溯搜索 + 当前最短上界剪枝staticvoidtspBacktrackBB(constvector<vector<int>>&distMat,intdepotIdx,constvector<int>&customerIdx,vector<int>&bestPath,int&bestCost){intm=(int)customerIdx.size();vector<int>path;vector<int>used(m,0);// 预计算最小边(用于下界估计)intglobalMinEdge=INT_MAX;for(inti=0;i<(int)distMat.size();i++)for(intj=0;j<(int)distMat.size();j++)if(i!=j&&distMat[i][j]<globalMinEdge)globalMinEdge=distMat[i][j];function<void(int,int,int)>dfs=[&](intdepth,intlastIdx,intcostSoFar){g_dfsCount++;// ===== 下界估计(分支限界核心)=====intremaining=m-depth;intlowerBound=costSoFar+remaining*globalMinEdge;if(lowerBound>=bestCost){g_pruneCount++;return;}if(depth==m){inttotal=costSoFar+distMat[lastIdx][depotIdx];if(total<bestCost){bestCost=total;bestPath=path;}return;}for(inti=0;i<m;i++){if(used[i])continue;intnxt=customerIdx[i];intadd=distMat[lastIdx][nxt];if(add>=(int)1e9)continue;used[i]=1;path.push_back(nxt);dfs(depth+1,nxt,costSoFar+add);path.pop_back();used[i]=0;}};dfs(0,depotIdx,0);}staticvector<int>buildRouteGreedyOrExact(constGraph&g,constvector<vector<int>>&distMat,intdepotId,constvector<int>&customerNodeIds){// ---------- 1. 贪心上界 ----------vector<int>greedy=buildRouteNearestNeighbor(g,distMat,depotId,customerNodeIds);autocalcCost=[&](constvector<int>&routeNodeId){intcost=0;for(inti=1;i<(int)routeNodeId.size();i++){inta=g.id2idx.at(routeNodeId[i-1]);intb=g.id2idx.at(routeNodeId[i]);cost+=distMat[a][b];}returncost;};intgreedyCost=calcCost(greedy);// ---------- 2. 客户点去重 ----------unordered_set<int>s;for(intnid:customerNodeIds)s.insert(nid);if((int)s.size()>10){cout<<"[提示] 客户点数量 > 10,自动使用贪心路线。\n";returngreedy;}// ---------- 3. 精确搜索 ----------vector<int>customerIdx;for(intnid:s)customerIdx.push_back(g.id2idx.at(nid));intdepotIdx=g.id2idx.at(depotId);intbestCost=greedyCost;vector<int>bestPermIdx;g_dfsCount=g_pruneCount=0;tspBacktrackBB(distMat,depotIdx,customerIdx,bestPermIdx,bestCost);cout<<"------ 路线优化对比(回溯 + 分支限界)------\n";cout<<"贪心路线距离: "<<greedyCost<<"\n";cout<<"最优路线距离: "<<bestCost<<"\n";cout<<"搜索节点数: "<<g_dfsCount<<"\n";cout<<"剪枝次数: "<<g_pruneCount<<"\n";if(bestCost<greedyCost){doubleimprove=100.0*(greedyCost-bestCost)/greedyCost;cout<<"优化率: "<<fixed<<setprecision(2)<<improve<<"%\n";}else{cout<<"未优于贪心(贪心已是最优或接近最优)\n";}cout<<"------------------------------------------\n";// ---------- 4. 构造最优路线 ----------vector<int>bestRouteNodeId;bestRouteNodeId.push_back(depotId);for(intidx:bestPermIdx)bestRouteNodeId.push_back(g.nodes[idx].id);bestRouteNodeId.push_back(depotId);returnbestRouteNodeId;}staticvoidtwoOptImprove(vector<int>&route,constGraph&g,constvector<vector<int>>&distMat){boolimproved=true;intn=route.size();autodist=[&](inta,intb){returndistMat[g.id2idx.at(a)][g.id2idx.at(b)];};while(improved){improved=false;for(inti=1;i<n-2;i++){for(intk=i+1;k<n-1;k++){intdelta=dist(route[i-1],route[k])+dist(route[i],route[k+1])-dist(route[i-1],route[i])-dist(route[k],route[k+1]);if(delta<0){reverse(route.begin()+i,route.begin()+k+1);improved=true;}}}}}// ---------- 路线距离 ----------staticintrouteDistance(constGraph&g,constvector<vector<int>>&distMat,constvector<int>&routeNodeIds){intsum=0;for(inti=1;i<(int)routeNodeIds.size();i++){inta=g.id2idx.at(routeNodeIds[i-1]);intb=g.id2idx.at(routeNodeIds[i]);sum+=distMat[a][b];}returnsum;}// ---------- 库存优化:动态规划 ----------// 目标:在预算 B 内,为每个物品选择一个补货方案(或不补),使“缺货罚金最小”(等价于满足最大)// 缺货量 = max(0, demand - (onHand + replenishQty))// 成本 = sum(option.cost)// 罚金 = sum(缺货量 * unitPenalty)// DP[itemIndex][budget] = 最小罚金staticvoidoptimizeInventoryDP(constvector<InventoryItem>&items,intbudget){intn=(int)items.size();constlonglongINF=(1LL<<60);vector<vector<longlong>>dp(n+1,vector<longlong>(budget+1,INF));vector<vector<int>>choice(n+1,vector<int>(budget+1,-1));// 记录选哪个 option(-1表示不补)dp[0][0]=0;autopenalty=[&](constInventoryItem&it,intaddQty)->longlong{inthave=it.onHand+addQty;intshortage=max(0,it.demand-have);return1LL*shortage*it.unitPenalty;};for(inti=1;i<=n;i++){constauto&it=items[i-1];for(intb=0;b<=budget;b++){// 不补货if(dp[i-1][b]<INF){longlongval=dp[i-1][b]+penalty(it,0);if(val<dp[i][b]){dp[i][b]=val;choice[i][b]=-1;}}// 选一个补货方案for(intk=0;k<(int)it.options.size();k++){intcost=it.options[k].cost;intqty=it.options[k].qty;if(b>=cost&&dp[i-1][b-cost]<INF){longlongval=dp[i-1][b-cost]+penalty(it,qty);if(val<dp[i][b]){dp[i][b]=val;choice[i][b]=k;}}}}}// 找到最优预算点intbestB=0;for(intb=1;b<=budget;b++){if(dp[n][b]<dp[n][bestB])bestB=b;}// 回溯方案vector<int>picked(n,-1);intb=bestB;for(inti=n;i>=1;i--){intc=choice[i][b];picked[i-1]=c;if(c!=-1)b-=items[i-1].options[c].cost;}// 输出cout<<"\n========== 库存优化(动态规划DP) ==========\n";cout<<"预算上限: "<<budget<<",最优使用预算: "<<bestB<<"\n";cout<<"最小缺货罚金: "<<dp[n][bestB]<<"\n\n";cout<<left<<setw(12)<<"物品"<<setw(8)<<"现有"<<setw(8)<<"需求"<<setw(10)<<"补货"<<setw(8)<<"成本"<<setw(10)<<"缺货"<<setw(10)<<"罚金"<<"\n";longlongtotalCost=0,totalPenalty=0;for(inti=0;i<n;i++){intaddQty=0,cost=0;if(picked[i]!=-1){addQty=items[i].options[picked[i]].qty;cost=items[i].options[picked[i]].cost;}inthave=items[i].onHand+addQty;intshortage=max(0,items[i].demand-have);longlongpen=1LL*shortage*items[i].unitPenalty;totalCost+=cost;totalPenalty+=pen;cout<<left<<setw(12)<<items[i].name<<setw(8)<<items[i].onHand<<setw(8)<<items[i].demand<<setw(10)<<addQty<<setw(8)<<cost<<setw(10)<<shortage<<setw(10)<<pen<<"\n";}cout<<"总成本: "<<totalCost<<",总罚金: "<<totalPenalty<<"\n";cout<<"===========================================\n";}// ---------- 打印基础数据 ----------staticvoidshowData(constGraph&g,constvector<Order>&orders,constvector<Vehicle>&vehicles,constvector<InventoryItem>&inv){cout<<"\n===== 节点 Nodes =====\n";for(auto&n:g.nodes)cout<<"Node "<<n.id<<" : "<<n.name<<"\n";cout<<"\n===== 订单 Orders =====\n";for(auto&o:orders){cout<<"Order "<<o.orderId<<" -> Node "<<o.nodeId<<" demand="<<o.demand<<" serviceTime="<<o.serviceTime<<"\n";}cout<<"\n===== 车辆 Vehicles =====\n";for(auto&v:vehicles){cout<<"Vehicle "<<v.vehId<<" cap="<<v.capacity<<" start="<<v.startTime<<"\n";}cout<<"\n===== 库存 Inventory =====\n";for(auto&it:inv){cout<<it.name<<" onHand="<<it.onHand<<" demand="<<it.demand<<" penalty="<<it.unitPenalty<<" options:";for(auto&op:it.options)cout<<" ("<<op.qty<<","<<op.cost<<")";cout<<"\n";}}// ---------- 主功能:规划配送(调度+路径) ----------staticvoidplanDelivery(constGraph&g,constvector<Order>&orders,constvector<Vehicle>&vehicles,booluseExactIfSmall){// 1) 带时间窗的贪心调度autoplans=scheduleVehiclesWithTimeWindow(orders,vehicles);// 2) 最短路距离矩阵autodistMat=allPairsShortestPathDist(g);unordered_map<int,Order>mp;for(auto&o:orders)mp[o.orderId]=o;cout<<"\n========== 车辆调度 + 路线规划结果 ==========\n";for(auto&rp:plans){if(rp.orderIds.empty()){cout<<"\n[车辆 "<<rp.vehId<<"] 无分配订单。\n";continue;}vector<int>customerNodes;for(intoid:rp.orderIds)customerNodes.push_back(mp[oid].nodeId);// 3) 初始路线vector<int>route;boolsmallScale=(unordered_set<int>(customerNodes.begin(),customerNodes.end()).size()<=10);if(useExactIfSmall&&smallScale){route=buildRouteGreedyOrExact(g,distMat,0,customerNodes);}else{route=buildRouteNearestNeighbor(g,distMat,0,customerNodes);}intbefore=routeDistance(g,distMat,route);// 4) 仅在大规模下启用 2-optif(!smallScale){twoOptImprove(route,g,distMat);}intafter=routeDistance(g,distMat,route);rp.visitNodes=route;rp.totalDistance=after;rp.finishTime+=after;// 距离≈时间(简化模型)cout<<"\n[车辆 "<<rp.vehId<<"] 分配订单: ";for(intoid:rp.orderIds)cout<<oid<<" ";cout<<"\n路线距离: "<<before;if(!smallScale)cout<<" → "<<after<<"(2-opt 优化 "<<fixed<<setprecision(2)<<100.0*(before-after)/before<<"%)";cout<<"\n预计完成时间: "<<rp.finishTime<<"\n路线: ";for(intnid:route){cout<<g.nodes[g.id2idx.at(nid)].name<<"("<<nid<<")";if(&nid!=&route.back())cout<<" -> ";}cout<<"\n";}cout<<"=======================================\n";}// ---------- 路径查询:Dijkstra 输出某两点最短路径 ----------staticvoidqueryShortestPath(constGraph&g){intsId,tId;cout<<"输入起点nodeId:";cin>>sId;cout<<"输入终点nodeId:";cin>>tId;if(!g.id2idx.count(sId)||!g.id2idx.count(tId)){cout<<"节点不存在。\n";return;}auto[dist,parent]=dijkstra(g,sId);intsIdx=g.id2idx.at(sId);inttIdx=g.id2idx.at(tId);if(dist[tIdx]>=(int)1e9){cout<<"不可达。\n";return;}autopathIdx=restorePathByIdx(parent,sIdx,tIdx);cout<<"最短距离 = "<<dist[tIdx]<<"\n路径:";for(inti=0;i<(int)pathIdx.size();i++){cout<<g.nodes[pathIdx[i]].name<<"("<<g.nodes[pathIdx[i]].id<<")";if(i+1<(int)pathIdx.size())cout<<" -> ";}cout<<"\n";}// ---------- 登录 ----------staticboollogin(intremain){string acc,pwd;cout<<"=========================================\n";cout<<" 智能物流配送系统(实验3 演示版)\n";cout<<"=========================================\n";cout<<"【登录提示】\n";cout<<" - 默认演示账号:1\n";cout<<" - 默认演示密码:123456\n";cout<<" - 剩余登录次数:"<<remain<<"\n";cout<<"-----------------------------------------\n";cout<<"请输入账号:";cin>>acc;cout<<"请输入密码:";cin>>pwd;if(acc==kAccount&&pwd==kPassword){cout<<"\n? 登录成功!欢迎进入系统。\n";cout<<"系统将自动加载示例数据用于算法演示。\n";returntrue;}else{cout<<"\n? 登录失败:账号或密码错误。\n";if(remain>1){cout<<"请重新输入(剩余 "<<remain-1<<" 次机会)。\n";}returnfalse;}}staticvoiddemoRouteOptimization(constGraph&g,constvector<Order>&orders){autodistMat=allPairsShortestPathDist(g);vector<int>customerNodes;for(auto&o:orders)customerNodes.push_back(o.nodeId);cout<<"\n=== 路线优化对比演示 ===\n";autogreedy=buildRouteNearestNeighbor(g,distMat,0,customerNodes);intd1=routeDistance(g,distMat,greedy);autoopt=greedy;twoOptImprove(opt,g,distMat);intd2=routeDistance(g,distMat,opt);cout<<"贪心路线距离: "<<d1<<"\n";cout<<"2-opt 优化后距离: "<<d2<<"\n";cout<<"优化率: "<<fixed<<setprecision(2)<<100.0*(d1-d2)/d1<<"%\n\n";cout<<"优化后路线:\n";for(intnid:opt){cout<<g.nodes[g.id2idx.at(nid)].name<<"("<<nid<<")";if(&nid!=&opt.back())cout<<" -> ";}cout<<"\n";}// ---------- 菜单 ----------staticvoidmenuLoop(){// 自动生成示例数据writeSampleDataIfMissing();// 加载数据Graph g=loadGraph();vector<Order>orders=loadOrders();vector<Vehicle>vehicles=loadVehicles();vector<InventoryItem>inv=loadInventory();while(true){cout<<"\n=============================\n";cout<<" 智能物流配送系统(实验3)\n";cout<<"=============================\n";cout<<"1. 查看基础数据\n";cout<<"2. 路径规划:两点最短路径(Dijkstra)\n";cout<<"3. 配送规划(时间窗调度 + 路线优化)\n";cout<<"4. 路线优化对比演示(贪心 vs 2-opt)\n";cout<<"5. 库存优化(动态规划 DP)\n";cout<<"6. 退出系统\n";cout<<"请输入功能编号:";intop;cin>>op;cls();if(op==1){showData(g,orders,vehicles,inv);pauseAny();cls();}elseif(op==2){queryShortestPath(g);pauseAny();cls();}elseif(op==3){cout<<"是否启用小规模精确路线优化(回溯+分支限界,<=10客户)?\n";cout<<"1 = 是(精确) 0 = 否(启发式)\n";intyes;cin>>yes;cout<<"\n【说明】系统将自动:\n";cout<<"- 使用带时间窗的贪心算法进行车辆调度\n";cout<<"- 小规模使用回溯,大规模使用 2-opt 优化\n\n";planDelivery(g,orders,vehicles,yes==1);pauseAny();cls();}elseif(op==4){demoRouteOptimization(g,orders);pauseAny();cls();}elseif(op==5){cout<<"输入库存补货总预算(建议 5~30):";intB;cin>>B;optimizeInventoryDP(inv,B);pauseAny();cls();}elseif(op==6){cout<<"退出。\n";break;}else{cout<<"无效输入。\n";pauseAny();cls();}}}intreadIntInRange(conststring&tip,intl,intr){intx;while(true){cout<<tip;if(cin>>x&&x>=l&&x<=r)returnx;cout<<"输入非法,请输入 ["<<l<<","<<r<<"] 之间的整数。\n";cin.clear();cin.ignore(numeric_limits<streamsize>::max(),'\n');}}intmain(){// 登录三次机会for(inti=0;i<3;i++){if(login(3-i)){cls();menuLoop();return0;}}cout<<"\n? 超过最大登录次数,系统已退出。\n";return0;}