حملونقل با صرفه مقیاس: وقتی محموله بزرگتر ارزانتر تمام میشود
بررسی مسئله حملونقل با هزینه حمل پلکانی و تخفیف حجمی؛ از فرمولبندی برنامهریزی عدد صحیح مختلط تا پیادهسازی با پایتون برای طراحی شبکه توزیع.
یک شرکت پخش مواد غذایی، هر هفته دهها محموله به فروشگاههای مختلف میفرستد. برای هر مسیر، چند گزینه حمل وجود دارد. محموله کوچک، نرخ هر تن بالاتری دارد. محموله بزرگتر، از تخفیف حجمی شرکت حملونقل بهره میبرد. مدیر لجستیک باید همزمان تصمیم بگیرد: از کدام انبار، به کدام فروشگاه، و با چه حجمی ارسال کند. انتخاب ساده بهنظر میرسد، اما ساختار هزینه پلکانی آن را پیچیده میکند.
این مسئله نسخه گسترشیافته مسئله کلاسیک حملونقل است. در مدل ساده، هزینه هر واحد ثابت و مستقل از حجم محموله فرض میشود. اما در دنیای واقعی، اغلب شرکتهای حملونقل نرخ پلکانی ارائه میدهند. محموله زیر چهل تن، نرخ بالا دارد؛ محموله بالای چهل تن، نرخ پایینتری میگیرد. همین ساختار هزینه، مسئله را از یک برنامه خطی ساده به یک مدل عدد صحیح مختلط تبدیل میکند.
اهمیت این موضوع در دنیای واقعی
نادیدهگرفتن تخفیف حجمی، هزینه واقعی حمل را بهشدت دستکم میگیرد. شرکتی مثل والمارت، روزانه هزاران محموله بین انبارهای توزیع و فروشگاههایش جابهجا میکند. تصمیم درباره حجم هر محموله، مستقیم روی هزینه کل ناوگان حمل اثر میگذارد. ادغام چند سفارش کوچک در یک محموله بزرگتر، گاهی دهها درصد در هزینه حمل صرفهجویی میکند.
این موضوع با طراحی شبکه توزیع هم پیوند مستقیم دارد. انتخاب اینکه کدام انبار به کدام فروشگاه سرویس بدهد، به ساختار هزینه حمل هر مسیر وابسته است. مسئله مکانیابی تسهیلات توزیع دقیقاً همین تعامل بین هزینه ثابت و هزینه حمل متغیر را بررسی میکند. دوره بهینهسازی زنجیره تأمین و حملونقل با پایتون هم مدلسازی این نوع تصمیمات شبکهای را پوشش میدهد.

فرمولبندی ریاضی مسئله
فرض کنید مجموعه مبادی (انبارها) را با و مجموعه مقاصد (فروشگاهها) را با نشان دهیم. عرضه هر انبار برابر و تقاضای هر مقصد برابر است. برای هر مسیر ، تابع هزینه حمل پلکانی است. سطح تعرفه داریم. آستانههای حجمی و نرخهای نزولی است.
متغیر نشان میدهد چه مقداری از مسیر در سطح تعرفه حمل میشود. متغیر دودویی هم نشان میدهد آیا این مسیر از سطح تعرفه استفاده میکند یا نه. هدف مدل، کمینهکردن هزینه کل حمل است:
هر مسیر فقط میتواند یک سطح تعرفه را فعال کند، و مقدار حمل در آن سطح باید بین دو آستانه بماند:
ظرفیت هر انبار و تقاضای هر فروشگاه هم باید رعایت شود:
این فرمولبندی، کل حجم هر مسیر را با نرخ همان سطح تعرفه قیمتگذاری میکند. این دقیقاً شبیه قراردادهای واقعی حمل است. وقتی محموله از یک آستانه عبور میکند، کل آن با نرخ پایینتر حساب میشود، نه فقط بخش اضافه. از نظر ریاضی، این یک تابع هزینه مقعر (Concave) است، چون نرخ نهایی هر واحد با افزایش حجم کاهش مییابد.
ظرفیت کار آکادمیک و پژوهشی
این حوزه جای کار پژوهشی زیادی دارد. مسیر اول، درنظرگرفتن عدمقطعیت در تقاضای هر فروشگاه است. مسیر دوم، ترکیب این مدل با انتخاب مسیر خودرو، یعنی بهینهسازی همزمان حجم محموله و توالی توزیع. مسیر سوم، مدلسازی قراردادهای چندساله با شرکتهای حملونقل است؛ جایی که آستانههای تعرفه خود موضوع مذاکرهاند.
جنبه دیگر، مقایسه روشهای حل دقیق با روشهای ابتکاری برای شبکههای بزرگ است. وقتی تعداد مسیرها و سطوح تعرفه زیاد شود، مدل عدد صحیح مختلط بهسرعت رشد میکند. اینکه روش دقیق تا چه اندازه عملی میماند و کِی باید سراغ ابتکاری رفت، پرسش مهمی است. پاسخ به آن، موضوع خوبی برای پایاننامه یا مقاله علمی است. ترکیب این مدل با هزینه کربن حمل هم آن را به حوزه زنجیره تأمین سبز نزدیک میکند.
پیادهسازی با پایتون
خبر خوب این است که حل این مدل، نیاز به سالور تجاری گرانقیمت ندارد. کتابخانه OR-Tools گوگل، با ماژول برنامهریزی خطی خود، برای این نوع مدل عدد صحیح مختلط کاملاً مناسب است. سالورهای متنباز مثل CBC یا HiGHS در پشت صحنه این کتابخانه، مسئله را بهخوبی حل میکنند. برای مدلسازی انعطافپذیرتر، کتابخانه Pyomo هم گزینه مناسبی است.
دادههای مسئله را میتوان از یک فایل اکسل یا CSV خواند. این فایل شامل نام انبارها و فروشگاهها، عرضه و تقاضای هر کدام است. آستانهها و نرخ هر سطح تعرفه هر مسیر هم در همان فایل میآید. کد زیر، نسخه ساده این مدل را با دو انبار، سه فروشگاه و دو سطح تعرفه حل میکند.
from ortools.linear_solver import pywraplp
solver = pywraplp.Solver.CreateSolver("CBC")
origins = ["انبار A", "انبار B"]
destinations = ["فروشگاه ۱", "فروشگاه ۲", "فروشگاه ۳"]
supply = {"انبار A": 120, "انبار B": 150}
demand = {"فروشگاه ۱": 80, "فروشگاه ۲": 90, "فروشگاه ۳": 100}
# سطوح تعرفه هر مسیر: (آستانه بالای سطح به تن، نرخ هر تن)
tiers = [(40, 12.0), (200, 7.5)]
x, y = {}, {}
for i in origins:
for j in destinations:
for k, (cap, rate) in enumerate(tiers):
prev_cap = tiers[k - 1][0] if k > 0 else 0
x[i, j, k] = solver.NumVar(0, cap, f"x_{i}_{j}_{k}")
y[i, j, k] = solver.IntVar(0, 1, f"y_{i}_{j}_{k}")
solver.Add(x[i, j, k] >= prev_cap * y[i, j, k])
solver.Add(x[i, j, k] <= cap * y[i, j, k])
solver.Add(sum(y[i, j, k] for k in range(len(tiers))) <= 1)
for i in origins:
solver.Add(sum(x[i, j, k] for j in destinations for k in range(len(tiers))) <= supply[i])
for j in destinations:
solver.Add(sum(x[i, j, k] for i in origins for k in range(len(tiers))) >= demand[j])
solver.Minimize(
sum(tiers[k][1] * x[i, j, k] for i in origins for j in destinations for k in range(len(tiers)))
)
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
for i in origins:
for j in destinations:
shipped = sum(x[i, j, k].solution_value() for k in range(len(tiers)))
if shipped > 0.01:
print(f"{i} به {j}: {shipped:.1f} تن")
خروجی این کد، دقیقترین ترکیب ارسال از هر انبار به هر فروشگاه را نشان میدهد. اگر تعداد مسیرها و سطوح تعرفه زیاد شود، همین ساختار متغیرها و قیود بهراحتی گسترش پیدا میکند. فقط کافی است فهرست تعرفه هر مسیر را از داده واقعی شرکت حملونقل بخوانید.
سوالات متداول
آیا این مدل فقط برای شرکتهای بزرگ توزیع کاربرد دارد؟
خیر. هر کسبوکاری که با چند گزینه حجم محموله و نرخ پلکانی حمل روبهرو است، از این مدل سود میبرد. حتی دو یا سه سطح تعرفه ساده هم صرفهجویی قابلتوجهی ایجاد میکند.
چه دورهای مدلسازی این نوع تصمیمات شبکه توزیع را آموزش میدهد؟
دوره بهینهسازی زنجیره تأمین و حملونقل با پایتون دقیقاً پایه مدلسازی این نوع مسائل تخصیص و شبکه توزیع را پوشش میدهد.
آیا امکان پیادهسازی اختصاصی این مدل برای شبکه توزیع ما وجود دارد؟
بله. تعداد انبارها، سطوح تعرفه هر مسیر و حتی قیود ظرفیت ناوگان، همگی قابل تنظیم با داده واقعی شما هستند. از طریق مشاوره میتوانیم جزئیات پروژه را بررسی کنیم.
مشاوره و ارتباط با ما
برای مشاوره و ثبتنام در دورهها و دریافت پروژهها با آیدی @pypyid در تلگرام در تماس باشید.