load-building-optimization について
輸送・物流向けの積載最適化スキルです。空間と重量の利用率を高めつつ、安定性、安全性、配送順を考慮したトラック積載計画を扱います。積載戦略、制約モデル、ヒューリスティックを紹介します。
主な機能
- 01空間・重量利用率の最適化
- 023D ビンパッキングとヒューリスティック
- 03積荷と車軸の重量配分
- 04配送順とゾーン積載
- 05貨物の不適合制約への対応
活用シーン
- 01複数地点配送の積載順序の計画
- 02トラック容量に合わせた貨物の混載
- 03重量配分と貨物の適合性の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill load-building-optimizationインストール後、Claude Code で/load-building-optimizationを入力して読み込まれたか確認します。
詳細
積載最適化
輸送とロジスティクスにおける積載計画およびトラック積載の最適化に精通しています。使用効率を最大化し、コストを最小限に抑え、安定性と安全性を確保し、出荷効率全体を向上させる最適なトラック積載を支援します。
初期評価
積載を最適化する前に、次の点を把握します。
-
車両の特性
- トレーラーの種類(ドライバン、冷蔵車、フラットベッド)?
- トレーラーの寸法(長さ × 幅 × 高さ)?
- 重量容量(総重量制限)?
- 車軸重量の制限?
- 床の耐荷重(psi)?
- 利用可能なトラックの台数?
-
出荷プロファイル
- 1日の出荷量(パレット、ケース)?
- 梱包の寸法と重量?
- 積み重ねの可否と壊れやすさ?
- 温度要件(常温、冷蔵、冷凍)?
- 配送順序とルート?
- 混載可能/不可の製品?
-
ビジネス要件
- トラックの台数を最小限に抑える?
- 容積使用率を最大化する?
- 配送時間枠を守る?
- 運賃を削減する?
- 製品の安全性を確保する(損傷を防ぐ)?
- ルート効率(立ち寄り順)?
-
現状
- 現在の容積使用率(%)?
- 平均重量使用率(%)?
- 積載計画の方法(手作業、ソフトウェア)?
- 運賃とその傾向?
- 損傷率?
積載計画のフレームワーク
積載計画の目標
主な目標:
- 空間使用率の最大化:トレーラーの容積を効率よく使う
- 重量使用率の最大化:重量容量を最大限に使う
- トラックの台数の最小化:混載してコストを削減する
- 荷重のバランス調整:適切に重量を配分し、荷崩れを防ぐ
- 安全性の確保:車軸の過積載を防ぎ、安定して積み重ねる
- ルートの最適化:積載順序を配送順に合わせる
主な指標:
- 容積使用率(%)(実容積 / トレーラー容量)
- 重量使用率(%)(実重量 / 容量)
- ポンドまたは立方フィートあたりのコスト
- 必要なトラックの台数
- 積載時間(荷物の積み付けと確認にかかる時間)
- 損傷率(出荷1,000件あたりのクレーム件数)
積載の戦略
1. 床から天井までの積載
- トレーラーの高さを最大限に使う
- 垂直方向の無駄な空間を最小限に抑える
- メリット:容積使用率を最大化できる
- デメリット:下段の荷物が損傷するリスクがある
- 用途:頑丈な製品、均一なパレット
2. 層ごとの積載
- 水平方向に層を作る
- 次の層に進む前に、現在の層を完成させる
- メリット:安定し、確認しやすい
- デメリット:垂直方向の空間が無駄になる場合がある
- 用途:壊れやすい品目、混載パレット
3. ゾーン積載(配送順)
- 配送先ごとに出荷品をまとめる
- 最後に降ろす荷物から先に積む(LIFO)
- メリット:配送時の荷扱いを最小限に抑えられる
- デメリット:容積使用率が下がる場合がある
- 用途:複数箇所に立ち寄るルート、LTL
4. 重量物を前方に積載
- 重い品目を前方(駆動軸の上)に置く
- 軽い品目を後方に置く
- メリット:重量配分とハンドリングが改善する
- デメリット:容積を最大限に使えない場合がある
- 用途:重量物やかさばる荷物、長距離輸送
5. テトリス/3Dビンパッキング
- テトリスのように最適な配置を行う
- アルゴリズムを使って積載密度を最大化する
- メリット:容積使用率が最も高くなる
- デメリット:複雑で、実際の作業では実行が難しい場合がある
- 用途:不定形の荷物、高価な貨物
数理モデル
3Dビンパッキング問題
決定変数:
- x[i,j] = 品目 i をトラック j に積載する場合は 1、そうでない場合は 0
- pos[i] = トラック内における品目 i の位置 (x, y, z)
- orient[i] = 品目 i の向き(回転)
パラメーター:
- L[i], W[i], H[i] = 品目 i の長さ、幅、高さ
- weight[i] = 品目 i の重量
- TL, TW, TH = トラックの長さ、幅、高さ
- T_weight = トラックの重量容量
- n = 品目数
- m = 利用可能なトラック数
目的関数:
Minimize: Number of trucks used
Subject to:
All items assigned
No overlapping items
Weight limits respected
Stability constraints satisfied
制約条件:
# 1. Each item assigned to exactly one truck
for i in items:
Σ x[i,j] = 1 for all j in trucks
# 2. Items within truck boundaries
for i in items:
for j in trucks:
if x[i,j] = 1:
pos[i].x + L[i] <= TL
pos[i].y + W[i] <= TW
pos[i].z + H[i] <= TH
# 3. No overlapping (simplified)
for i, k in items (i != k):
for j in trucks:
if x[i,j] = 1 and x[k,j] = 1:
# One of these must be true:
pos[i].x + L[i] <= pos[k].x OR
pos[k].x + L[k] <= pos[i].x OR
pos[i].y + W[i] <= pos[k].y OR
pos[k].y + W[k] <= pos[i].y OR
pos[i].z + H[i] <= pos[k].z OR
pos[k].z + H[k] <= pos[i].z
# 4. Weight capacity
for j in trucks:
Σ (weight[i] × x[i,j]) <= T_weight for all i
# 5. Support constraint (item must rest on floor or another item)
for i in items:
if pos[i].z > 0:
must have sufficient support area underneath
# 6. Stackability
for i, k in items:
if item i on top of item k:
stackable[k] must be True
weight_on_top[k] <= max_stack_weight[k]
これは NP 困難な問題であるため、実用的な解法ではヒューリスティックを使用します。
積載アルゴリズム
First-Fit Decreasing(FFD)ヒューリスティック
import numpy as np
import pandas as pd
def first_fit_decreasing_load_building(shipments, truck_capacity):
"""
First-Fit Decreasing heuristic for load building
Algorithm:
1. Sort shipments by volume (largest first)
2. For each shipment, try to fit in first truck with space
3. If doesn't fit, create new truck
Parameters:
-----------
shipments : DataFrame
Columns: shipment_id, weight, volume, length, width, height
truck_capacity : dict
{'weight': max_weight, 'volume': max_volume}
Returns:
--------
Load plan with truck assignments
"""
# Sort by volume (largest first)
shipments_sorted = shipments.sort_values('volume', ascending=False).copy()
trucks = []
current_truck = {
'truck_id': 1,
'shipments': [],
'total_weight': 0,
'total_volume': 0
}
for idx, shipment in shipments_sorted.iterrows():
ship_weight = shipment['weight']
ship_volume = shipment['volume']
# Try to fit in current truck
if (current_truck['total_weight'] + ship_weight <= truck_capacity['weight'] and
current_truck['total_volume'] + ship_volume <= truck_capacity['volume']):
# Fits in current truck
current_truck['shipments'].append(shipment['shipment_id'])
current_truck['total_weight'] += ship_weight
current_truck['total_volume'] += ship_volume
else:
# Doesn't fit, start new truck
trucks.append(current_truck)
current_truck = {
'truck_id': len(trucks) + 1,
'shipments': [shipment['shipment_id']],
'total_weight': ship_weight,
'total_volume': ship_volume
}
# Add last truck
if current_truck['shipments']:
trucks.append(current_truck)
# Calculate utilization
for truck in trucks:
truck['weight_util'] = (truck['total_weight'] / truck_capacity['weight']) * 100
truck['volume_util'] = (truck['total_volume'] / truck_capacity['volume']) * 100
return pd.DataFrame(trucks)
# Example usage
shipments = pd.DataFrame({
'shipment_id': [f'S{i:03d}' for i in range(1, 51)],
'weight': np.random.uniform(500, 5000, 50), # lbs
'volume': np.random.uniform(50, 500, 50), # cubic feet
'length': np.random.uniform(3, 8, 50), # feet
'width': np.random.uniform(3, 4, 50),
'height': np.random.uniform(3, 6, 50)
})
truck_capacity = {
'weight': 45000, # lbs (typical 53' dry van)
'volume': 4000 # cubic feet
}
load_plan = first_fit_decreasing_load_building(shipments, truck_capacity)
print("Load Building Results (First-Fit Decreasing):")
print(f"Total Trucks: {len(load_plan)}")
print(f"\nTruck Summary:")
print(load_plan[['truck_id', 'total_weight', 'total_volume',
'weight_util', 'volume_util']])
print(f"\nAverage Utilization:")
print(f" Weight: {load_plan['weight_util'].mean():.1f}%")
print(f" Volume: {load_plan['volume_util'].mean():.1f}%")
配送順を考慮した Best-Fit Decreasing
def best_fit_with_route_sequence(shipments, truck_capacity, route_sequence):
"""
Best-fit load building considering delivery sequence
Ensure items delivered first are loaded last (LIFO)
Parameters:
-----------
shipments : DataFrame
With route_stop column indicating delivery order
truck_capacity : dict
route_sequence : list
Ordered list of stops
Returns:
--------
Load plan with sequence constraints
"""
# Group shipments by route stop
shipments_by_stop = shipments.groupby('route_stop')
trucks = []
# Reverse route sequence (load last stop first)
for stop in reversed(route_sequence):
if stop not in shipments_by_stop.groups:
continue
stop_shipments = shipments_by_stop.get_group(stop)
stop_shipments_sorted = stop_shipments.sort_values('volume', ascending=False)
# Try to fit stop's shipments into existing trucks
for idx, shipment in stop_shipments_sorted.iterrows():
ship_weight = shipment['weight']
ship_volume = shipment['volume']
placed = False
# Try existing trucks (prefer truck with most remaining space)
for truck in sorted(trucks,
key=lambda t: (truck_capacity['volume'] - t['total_volume']),
reverse=True):
if (truck['total_weight'] + ship_weight <= truck_capacity['weight'] and
truck['total_volume'] + ship_volume <= truck_capacity['volume']):
# Fits in this truck
truck['shipments'].append(shipment['shipment_id'])
truck['stops'].add(stop)
truck['total_weight'] += ship_weight
truck['total_volume'] += ship_volume
placed = True
break
if not placed:
# Create new truck
trucks.append({
'truck_id': len(trucks) + 1,
'shipments': [shipment['shipment_id']],
'stops': {stop},
'total_weight': ship_weight,
'total_volume': ship_volume
})
# Calculate utilization
for truck in trucks:
truck['weight_util'] = (truck['total_weight'] / truck_capacity['weight']) * 100
truck['volume_util'] = (truck['total_volume'] / truck_capacity['volume']) * 100
truck['num_stops'] = len(truck['stops'])
truck['stops'] = list(truck['stops'])
return pd.DataFrame(trucks)
# Example with route stops
shipments_routed = shipments.copy()
shipments_routed['route_stop'] = np.random.choice(['Stop_A', 'Stop_B', 'Stop_C', 'Stop_D'], 50)
route_sequence = ['Stop_A', 'Stop_B', 'Stop_C', 'Stop_D']
load_plan_routed = best_fit_with_route_sequence(
shipments_routed, truck_capacity, route_sequence
)
print("\nLoad Building with Route Sequence:")
print(load_plan_routed[['truck_id', 'num_stops', 'total_weight', 'weight_util']])
3Dビンパッキングのヒューリスティック
class Container3D:
"""Represent a truck/container for 3D packing"""
def __init__(self, length, width, height, weight_limit):
self.length = length
self.width = width
self.height = height
self.weight_limit = weight_limit
self.items = []
self.total_weight = 0
self.spaces = [(0, 0, 0, length, width, height)] # Available spaces
def can_fit(self, item_length, item_width, item_height, item_weight):
"""Check if item can fit in any available space"""
if self.total_weight + item_weight > self.weight_limit:
return False
for space in self.spaces:
sx, sy, sz, sl, sw, sh = space
# Try all 6 orientations
orientations = [
(item_length, item_width, item_height),
(item_length, item_height, item_width),
(item_width, item_length, item_height),
(item_width, item_height, item_length),
(item_height, item_length, item_width),
(item_height, item_width, item_length)
]
for l, w, h in orientations:
if l <= sl and w <= sw and h <= sh:
return True, space, (l, w, h)
return False, None, None
def place_item(self, item_id, item_length, item_width, item_height, item_weight):
"""Place item in best available space"""
can_fit_result = self.can_fit(item_length, item_width, item_height, item_weight)
if can_fit_result[0]:
space, orientation = can_fit_result[1], can_fit_result[2]
sx, sy, sz, sl, sw, sh = space
l, w, h = orientation
# Place item at corner of space
self.items.append({
'item_id': item_id,
'position': (sx, sy, sz),
'dimensions': (l, w, h),
'weight': item_weight
})
self.total_weight += item_weight
# Remove used space and create new available spaces
self.spaces.remove(space)
# Create new spaces (simplified - guillotine cuts)
# Right space
if sl - l > 0:
self.spaces.append((sx + l, sy, sz, sl - l, sw, sh))
# Front space
if sw - w > 0:
self.spaces.append((sx, sy + w, sz, l, sw - w, sh))
# Top space
if sh - h > 0:
self.spaces.append((sx, sy, sz + h, l, w, sh - h))
# Sort spaces by position (bottom-left-front first)
self.spaces.sort(key=lambda s: (s[2], s[1], s[0]))
return True
return False
def pack_3d_containers(items, container_dims, container_weight_limit):
"""
Pack items into containers using 3D bin packing
Parameters:
-----------
items : DataFrame
Columns: item_id, length, width, height, weight
container_dims : tuple
(length, width, height) of container
container_weight_limit : float
Returns:
--------
List of packed containers
"""
# Sort items by volume (largest first)
items_sorted = items.copy()
items_sorted['volume'] = (items_sorted['length'] *
items_sorted['width'] *
items_sorted['height'])
items_sorted = items_sorted.sort_values('volume', ascending=False)
containers = []
current_container = Container3D(*container_dims, container_weight_limit)
for idx, item in items_sorted.iterrows():
placed = current_container.place_item(
item['item_id'],
item['length'],
item['width'],
item['height'],
item['weight']
)
if not placed:
# Start new container
containers.append(current_container)
current_container = Container3D(*container_dims, container_weight_limit)
# Try again with new container
placed = current_container.place_item(
item['item_id'],
item['length'],
item['width'],
item['height'],
item['weight']
)
if not placed:
print(f"Warning: Could not place item {item['item_id']}")
# Add last container
if current_container.items:
containers.append(current_container)
return containers
# Example
container_dims = (53, 8.5, 9) # 53' trailer: length, width, height (feet)
container_weight_limit = 45000 # lbs
# Convert shipments to feet for dimensions
items_3d = shipments.copy()
containers = pack_3d_containers(items_3d, container_dims, container_weight_limit)
print(f"\n3D Bin Packing Results:")
print(f"Total Containers: {len(containers)}")
for i, container in enumerate(containers):
volume_used = sum(
item['dimensions'][0] * item['dimensions'][1] * item['dimensions'][2]
for item in container.items
)
total_volume = container.length * container.width * container.height
print(f"\nContainer {i+1}:")
print(f" Items: {len(container.items)}")
print(f" Weight: {container.total_weight:,.0f} lbs "
f"({container.total_weight / container_weight_limit * 100:.1f}%)")
print(f" Volume: {volume_used / total_volume * 100:.1f}% utilized")
高度な積載手法
重量配分と車軸荷重
def calculate_axle_weights(items_in_truck, truck_length=53):
"""
Calculate weight on each axle to ensure compliance
Truck has:
- Steer axle (front)
- Drive axles (middle)
- Trailer axles (rear)
Parameters:
-----------
items_in_truck : list
Items with position and weight
truck_length : float
Truck length in feet
Returns:
--------
Axle weights and compliance
"""
# Axle positions (simplified)
steer_position = 0
drive_position = 20 # feet from front
trailer_position = 43 # feet from front
steer_weight = 0
drive_weight = 0
trailer_weight = 0
# Calculate center of gravity for each item
for item in items_in_truck:
position_x = item['position'][0] # Distance from front
item_cog_x = position_x + item['dimensions'][0] / 2
item_weight = item['weight']
# Distribute weight to axles based on distance
# Simplified: closest axle gets weight
dist_to_steer = abs(item_cog_x - steer_position)
dist_to_drive = abs(item_cog_x - drive_position)
dist_to_trailer = abs(item_cog_x - trailer_position)
min_dist = min(dist_to_steer, dist_to_drive, dist_to_trailer)
if min_dist == dist_to_steer:
steer_weight += item_weight
elif min_dist == dist_to_drive:
drive_weight += item_weight
else:
trailer_weight += item_weight
# Legal limits (example - varies by jurisdiction)
limits = {
'steer': 12000, # lbs
'drive': 34000, # lbs (tandem)
'trailer': 34000 # lbs (tandem)
}
compliant = (
steer_weight <= limits['steer'] and
drive_weight <= limits['drive'] and
trailer_weight <= limits['trailer']
)
return {
'steer_weight': steer_weight,
'drive_weight': drive_weight,
'trailer_weight': trailer_weight,
'total_weight': steer_weight + drive_weight + trailer_weight,
'compliant': compliant,
'violations': {
'steer': max(0, steer_weight - limits['steer']),
'drive': max(0, drive_weight - limits['drive']),
'trailer': max(0, trailer_weight - limits['trailer'])
}
}
# Example
if len(containers) > 0:
axle_weights = calculate_axle_weights(containers[0].items)
print("\nAxle Weight Distribution:")
print(f" Steer Axle: {axle_weights['steer_weight']:,.0f} lbs")
print(f" Drive Axle: {axle_weights['drive_weight']:,.0f} lbs")
print(f" Trailer Axle: {axle_weights['trailer_weight']:,.0f} lbs")
print(f" Total: {axle_weights['total_weight']:,.0f} lbs")
print(f" Compliant: {'Yes' if axle_weights['compliant'] else 'No'}")
混載不可条件を考慮した積載最適化
def load_with_incompatibilities(shipments, truck_capacity, incompatible_pairs):
"""
Load building with product incompatibility constraints
Some products cannot be shipped together:
- Food and chemicals
- Different temperature requirements
- Hazmat restrictions
Parameters:
-----------
shipments : DataFrame
truck_capacity : dict
incompatible_pairs : list of tuples
[(product_type_1, product_type_2), ...]
Returns:
--------
Load plan respecting incompatibilities
"""
from pulp import *
# Create optimization model
prob = LpProblem("Load_Building_Incompatibility", LpMinimize)
# Maximum trucks needed (upper bound)
max_trucks = len(shipments)
trucks = range(max_trucks)
# Decision variables
# x[i,j] = 1 if shipment i in truck j
x = LpVariable.dicts("load",
[(i, j) for i in shipments.index for j in trucks],
cat='Binary')
# y[j] = 1 if truck j is used
y = LpVariable.dicts("use_truck", trucks, cat='Binary')
# Objective: minimize number of trucks
prob += lpSum([y[j] for j in trucks]), "Minimize_Trucks"
# Constraints
# 1. Each shipment in exactly one truck
for i in shipments.index:
prob += lpSum([x[i, j] for j in trucks]) == 1, f"Shipment_{i}"
# 2. Weight capacity
for j in trucks:
prob += lpSum([
shipments.loc[i, 'weight'] * x[i, j]
for i in shipments.index
]) <= truck_capacity['weight'] * y[j], f"Weight_{j}"
# 3. Volume capacity
for j in trucks:
prob += lpSum([
shipments.loc[i, 'volume'] * x[i, j]
for i in shipments.index
]) <= truck_capacity['volume'] * y[j], f"Volume_{j}"
# 4. Incompatibility constraints
for (type1, type2) in incompatible_pairs:
# Find shipments of each type
shipments_type1 = shipments[shipments['product_type'] == type1].index
shipments_type2 = shipments[shipments['product_type'] == type2].index
# For each truck, can't have both types
for j in trucks:
# If any type1 in truck j, no type2 can be in truck j
for i1 in shipments_type1:
for i2 in shipments_type2:
prob += x[i1, j] + x[i2, j] <= 1, \
f"Incompatible_{i1}_{i2}_{j}"
# 5. Link shipment assignment to truck usage
for j in trucks:
for i in shipments.index:
prob += x[i, j] <= y[j], f"Link_{i}_{j}"
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract solution
trucks_used = []
for j in trucks:
if y[j].varValue > 0.5:
truck_shipments = [
i for i in shipments.index
if x[i, j].varValue > 0.5
]
if truck_shipments:
total_weight = shipments.loc[truck_shipments, 'weight'].sum()
total_volume = shipments.loc[truck_shipments, 'volume'].sum()
trucks_used.append({
'truck_id': j + 1,
'shipments': truck_shipments,
'num_shipments': len(truck_shipments),
'total_weight': total_weight,
'total_volume': total_volume,
'weight_util': total_weight / truck_capacity['weight'] * 100,
'volume_util': total_volume / truck_capacity['volume'] * 100
})
return {
'status': LpStatus[prob.status],
'trucks': pd.DataFrame(trucks_used),
'num_trucks': len(trucks_used)
}
# Example
shipments_typed = shipments.copy()
shipments_typed['product_type'] = np.random.choice(
['Food', 'Chemical', 'Electronics', 'Apparel'], 50
)
incompatible_pairs = [
('Food', 'Chemical'),
('Electronics', 'Chemical')
]
result_incomp = load_with_incompatibilities(
shipments_typed, truck_capacity, incompatible_pairs
)
print(f"\nLoad Building with Incompatibilities:")
print(f"Status: {result_incomp['status']}")
print(f"Trucks Required: {result_incomp['num_trucks']}")
print("\nTruck Details:")
print(result_incomp['trucks'][['truck_id', 'num_shipments', 'weight_util', 'volume_util']])
ツールとライブラリ
積載計画ソフトウェア
輸送管理システム(TMS):
- MercuryGate TMS:積載の最適化と計画
- Oracle Transportation Management:積載計画モジュール
- Blue Yonder (JDA) TMS:積載最適化
- E2open TMS:積載の自動最適化
専用の積載計画ソフトウェア:
- TOPS Load Planning:3D 積載最適化
- CargoWiz:コンテナとトラックの積載計画
- CubiScan:寸法測定と積載計画
- Cargo Optimizer:高度な積載計画
- LoadMaster:トラックとコンテナへの積載
倉庫管理システム:
- Manhattan WMS:積載計画の統合
- SAP EWM:積載計画と最適化
Python ライブラリ
# Optimization
from pulp import * # MIP modeling
from ortools.linear_solver import pywraplp # Google OR-Tools
# 3D Packing
from py3dbp import Packer, Bin, Item # 3D bin packing library
# Geometry and Visualization
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import pandas as pd
よくある課題と解決策
課題:容積と重量のトレードオフ
問題:
- 容積を満たす前に重量上限に達する(高密度の製品)
- または、重量に余裕がある状態で容積上限に達する(かさばる軽量品)
- 「容積上限に達する」か「重量上限に達する」か
解決策:
- 同じ積載物に高密度の貨物と軽量の貨物を混載する
- 貨物クラスを使って不均衡を特定する
- 運賃($/lb と $/cuft)に基づいて優先順位を付ける
- 貨物の種類を組み合わせるために、複数箇所に立ち寄るルートを検討する
- 容積データを正確に取得するため、寸法測定装置を使用する
課題:ルート順序の競合
問題:
- 最適な積載配置が配送順序と合わない
- 1番目の停車地より先に3番目の停車地の貨物を降ろす必要がある(順序が逆)
- 配送時の積み直しが過剰になる
解決策:
- 配送順序と逆の順番で積み込む(後入れ先出し:LIFO)
- 区画ごとに積み込む(停車地ごとにエリアを割り当てる)
- 複数箇所に立ち寄るルートでは、積載率の低下を許容する
- 順序が競合する停車地には、直送を検討する
- 停車地ごとにパレット化する(停車地1=パレット1~5など)
課題:製品の混載不可条件
問題:
- 食品は化学薬品と一緒に輸送できない(汚染)
- 温度帯(冷凍、冷蔵、常温)
- 危険物規制(混載不可のクラス)
- 臭いの移り(魚、香水)
解決策:
- 混載できない製品には別々のトラックを使用する
- トラック内に物理的な仕切りを設ける
- 積載区画を厳格に分ける(前方=食品、後方=食品以外)
- 適切な梱包と密封を行う
- TMS/WMS で混載不可マトリクスを管理する
課題:形状が不規則な荷物
問題:
- 直方体ではない荷物(ドラム缶、コイル、機械)
- 標準的なアルゴリズムでは効率よく積み込めない
- 不規則な形状の周囲に空間が無駄になる
解決策:
- 複雑な荷物にはカスタム3Dモデリングを使用する
- 緩衝材や隙間充填材を使用する
- 規格外の荷物専用のトラックを用意する
- 重量のある不規則な荷物は床積みする
- 正確なモデルを作成するため、写真撮影と3Dスキャンを行う
課題:直前の変更
問題:
- 積載計画の作成後に注文が追加またはキャンセルされる
- その場で再最適化が必要になる
- 積み込み済みのトラックを調整しなければならない
解決策:
- 変更に備えて、容量の10~15%を確保する
- リアルタイムの再最適化アルゴリズムを使用する
- 積載計画の「時間枠」を設ける(出荷の2時間前に確定する)
- 柔軟な積載順序にする(追加分を所定の場所に積む)
- 締め切り時刻を明確に伝える
出力形式
積載計画レポート
トラック積載計画 - トラック #TRK-001
トラック仕様:
- 種類:53' ドライバン
- 積載量:45,000 lbs、4,000 cu ft
- 寸法:53' L × 8.5' W × 9' H
積載概要:
| 指標 | 値 | 積載率 |
|---|---|---|
| 総重量 | 42,850 lbs | 95% |
| 総容積 | 3,420 cu ft | 86% |
| パレット数 | 24 | |
| 出荷数 | 18 | |
| 停車数 | 3 |
対象出荷:
| 出荷 | 顧客 | 停車地 | 重量 | 容積 | 寸法 |
|---|---|---|---|---|---|
| S001 | Acme Corp | 1 | 2,400 lbs | 180 cuft | 4×4×6 ft |
| S002 | Beta Inc | 1 | 1,850 lbs | 145 cuft | 4×4×5 ft |
| S005 | Gamma LLC | 2 | 3,200 lbs | 220 cuft | 4×4×7 ft |
| ... | ... | ... | ... | ... | ... |
積載順序(前方から後方):
Zone 1 (Stop 3 - Last Off): Shipments S015-S018
- 8 pallets
- 12,450 lbs
- Positions: Rows 1-2
Zone 2 (Stop 2): Shipments S005-S014
- 10 pallets
- 18,200 lbs
- Positions: Rows 3-5
Zone 3 (Stop 1 - First Off): Shipments S001-S004
- 6 pallets
- 12,200 lbs
- Positions: Rows 6-7 (rear)
重量配分:
- 操舵軸:11,200 lbs(上限12,000 lbsの93%) ✓
- 駆動軸:32,850 lbs(上限34,000 lbsの97%) ✓
- トレーラー軸:31,650 lbs(上限34,000 lbsの93%) ✓
- 合計:42,850 lbs - 適合
積載図:
Front (Cab) Rear (Doors)
|------------|------------|------------|------------|------------|
| Zone 3 | Zone 2 | Zone 1 |
| Stop 1 | Stop 2 | Stop 3 |
| (First Off)| (Second Off) | (Last Off) |
|------------|------------|------------|------------|------------|
Rows 6-7 Rows 3-5 Rows 1-2
6 pallets 10 pallets 8 pallets
代替計画とのパフォーマンス比較:
| 計画 | トラック数 | 平均重量積載率 | 平均容積積載率 | コスト |
|---|---|---|---|---|
| 最適化(現在) | 3 | 94% | 85% | $2,850 |
| ルート優先積載 | 4 | 78% | 72% | $3,800 |
| 手動積載 | 4 | 81% | 68% | $3,800 |
| 削減額 | 25% | $950 |
推奨事項:
- 積載率は優秀です。バランスの取れた積載です
- パレットをあと2つ追加することを検討してください(積載余力があります)
- 積載中は車軸重量を監視してください
確認事項
さらに詳しい情報が必要な場合:
- トラック/トレーラーの種類は何ですか(ドライバン、冷蔵車、フラットベッドなど)?
- トレーラーの寸法と重量制限を教えてください
- 1日あたりの出荷量はどのくらいですか?
- 積載は単一停車地向けですか、それとも複数停車地向けですか?
- 現在の容積/重量積載率はどのくらいですか?
- 製品の相性による問題や制限はありますか?
- 現在、どのような積載計画方法を使用していますか?
- 出荷品の寸法は正確に把握できていますか?
関連スキル
- pallet-loading:パレット配置の最適化
- container-loading-optimization:輸送コンテナ向け
- vehicle-loading-optimization:各種車両向け
- 3d-bin-packing:3D 梱包アルゴリズム向け
- route-optimization:積載計画とルートの調整
- freight-optimization:貨物コストの最適化
- knapsack-problems:梱包に関する理論的背景
- warehouse-slotting-optimization:積載前の出荷品の仮置き
コメント
Markdown 対応