一个简单的机位分配的demo

from ortools.sat.python import cp_model
import heapq

INF = 10**12


def get_taxi_time_by_dp(plane, stand, airport_map):
    """
    动态规划 / 最短路函数:计算某架飞机到某个机位的最短滑行时长。

    输入:
        plane:
            {
                "id": "P1",
                "start": (0, 0)
            }

        stand:
            {
                "id": "G1",
                "pos": (4, 5)
            }

        airport_map:
            二维网格地图。
            airport_map[r][c] = 0 表示不可通行;
            airport_map[r][c] > 0 表示可通行,并表示进入该格子的滑行耗时。

    返回:
        taxi_time: 最短滑行时长,整数
        path: 最短滑行路径
    """

    start = plane["start"]
    target = stand["pos"]

    rows = len(airport_map)
    cols = len(airport_map[0])

    if airport_map[start[0]][start[1]] == 0:
        return INF, []

    if airport_map[target[0]][target[1]] == 0:
        return INF, []

    # dp[r][c] 表示从飞机起点滑行到位置 (r, c) 的最短时长
    dp = [[INF for _ in range(cols)] for _ in range(rows)]
    parent = [[None for _ in range(cols)] for _ in range(rows)]

    dp[start[0]][start[1]] = 0

    # 这里用优先队列求最短滑行时长。
    # 如果你的机场滑行道是 DAG,也可以替换成严格的拓扑 DP。
    heap = [(0, start)]

    directions = [
        (-1, 0),  # 上
        (1, 0),  # 下
        (0, -1),  # 左
        (0, 1),  # 右
    ]

    while heap:
        current_time, current = heapq.heappop(heap)
        r, c = current

        if current_time > dp[r][c]:
            continue

        if current == target:
            break

        for dr, dc in directions:
            nr = r + dr
            nc = c + dc

            if nr < 0 or nr >= rows or nc < 0 or nc >= cols:
                continue

            if airport_map[nr][nc] == 0:
                continue

            next_time = current_time + airport_map[nr][nc]

            if next_time < dp[nr][nc]:
                dp[nr][nc] = next_time
                parent[nr][nc] = (r, c)
                heapq.heappush(heap, (next_time, (nr, nc)))

    taxi_time = dp[target[0]][target[1]]

    if taxi_time >= INF:
        return INF, []

    path = []
    cur = target

    while cur is not None:
        path.append(cur)
        cur = parent[cur[0]][cur[1]]

    path.reverse()

    return int(taxi_time), path


def assign_planes_to_stands_by_min_taxi_time(planes, stands, airport_map):
    """
    使用 OR-Tools 求解飞机-机位分配问题,使总滑行时长最短。

    决策变量:
        x[i, j] = 1 表示第 i 架飞机分配到第 j 个机位

    目标:
        min sum(taxi_time[i, j] * x[i, j])
    """

    m = len(planes)
    n = len(stands)

    if m > n:
        raise ValueError(
            "飞机数量 m 不能大于机位数量 n,否则无法保证每架飞机都有机位。"
        )

    model = cp_model.CpModel()

    x = {}
    taxi_time = {}
    taxi_paths = {}

    for i in range(m):
        for j in range(n):
            time_value, path = get_taxi_time_by_dp(planes[i], stands[j], airport_map)

            taxi_time[i, j] = time_value
            taxi_paths[i, j] = path

            x[i, j] = model.NewBoolVar(f"x_{i}_{j}")

            # 如果飞机到该机位不可达,则禁止该分配
            if time_value >= INF:
                model.Add(x[i, j] == 0)

    # 每架飞机必须分配到一个机位
    for i in range(m):
        model.Add(sum(x[i, j] for j in range(n)) == 1)

    # 每个机位最多分配一架飞机
    for j in range(n):
        model.Add(sum(x[i, j] for i in range(m)) <= 1)

    # 目标函数:总滑行时长最短
    model.Minimize(sum(taxi_time[i, j] * x[i, j] for i in range(m) for j in range(n)))

    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    if status not in (cp_model.OPTIMAL, cp_model.FEASIBLE):
        return None

    assignments = []
    total_taxi_time = 0

    for i in range(m):
        for j in range(n):
            if solver.Value(x[i, j]) == 1:
                selected_time = taxi_time[i, j]
                total_taxi_time += selected_time

                assignments.append(
                    {
                        "plane_id": planes[i]["id"],
                        "stand_id": stands[j]["id"],
                        "taxi_time": selected_time,
                        "path": taxi_paths[i, j],
                    }
                )

    return {
        "total_taxi_time": total_taxi_time,
        "assignments": assignments,
    }


if __name__ == "__main__":
    # m 个飞机
    planes = [
        {"id": "P1", "start": (0, 0)},
        {"id": "P2", "start": (1, 0)},
        {"id": "P3", "start": (2, 0)},
    ]

    # n 个机位
    stands = [
        {"id": "G1", "pos": (3, 3)},
        {"id": "G2", "pos": (4, 4)},
        {"id": "G3", "pos": (2, 5)},
        {"id": "G4", "pos": (5, 5)},
    ]

    # 机场滑行地图
    # 0 表示不能通行
    # 正数表示进入该位置需要的滑行时长
    airport_map = [
        [1, 1, 1, 2, 2, 2],
        [1, 0, 1, 0, 3, 2],
        [1, 1, 1, 1, 2, 1],
        [2, 0, 2, 1, 1, 1],
        [2, 2, 2, 0, 1, 1],
        [3, 3, 2, 1, 1, 1],
    ]

    solution = assign_planes_to_stands_by_min_taxi_time(planes, stands, airport_map)

    if solution is None:
        print("无可行分配方案")
    else:
        print("最短总滑行时长:", solution["total_taxi_time"])
        print("分配结果:")

        for item in solution["assignments"]:
            print(
                f"飞机 {item['plane_id']} -> 机位 {item['stand_id']}, "
                f"滑行时长 = {item['taxi_time']}, "
                f"路径 = {item['path']}"
            )

posted on 2026-09-16 15:28  漫思  阅读(2)  评论(0)    收藏  举报

导航