# API Reference


Source: https://docs.fleetwork.vn/sdk/optimize-api

> Tài liệu kỹ thuật cho dịch vụ tối ưu lộ trình Optimize tại `https://live.fleetwork.vn/api/v1/optimize`.

---

## Base Path

```http
POST https://live.fleetwork.vn/api/v1/optimize
Content-Type: application/json
X-API-Key: <your_api_key>
```

> API này nhận payload JSON theo format đầu vào và trả về kết quả tối ưu dưới dạng JSON.

---

## Phạm vi tài liệu

Tài liệu này mô tả:

- schema request cho bài toán Vehicle Routing Problem (Optimize)
- schema response của kết quả tối ưu
- ý nghĩa các object, field và ràng buộc dữ liệu
- các quy ước đơn vị đo và format thời gian

Tài liệu mô tả 2 chế độ xử lý:

- **Solving mode**: tối ưu lộ trình mặc định
- **Plan mode**: tính ETA cho route đã được mô tả trước

Tài liệu này tập trung vào **payload contract** dùng chung cho hai chế độ. Cách backend `/api/v1/optimize` chọn mode thực thi phụ thuộc implementation của dịch vụ triển khai.

---

## Authentication

API xác thực qua **request header**:

| Header         | Giá trị             |
| -------------- | ------------------- |
| `X-API-Key`    | API key của account |
| `Content-Type` | `application/json`  |

> ⚠️ **Không cần** truyền `X-Internal-Token` hay `X-Account-Id` — gateway tự inject.

Sai hoặc thiếu key sẽ trả về `401 Unauthorized` (no body — ASP.NET default).

---

## Quy ước dữ liệu

| Quy ước             | Giá trị                                       |
| ------------------- | --------------------------------------------- |
| Thứ tự tọa độ       | `[lon, lat]`                                  |
| Thời gian           | `seconds`                                     |
| Khoảng cách         | `meters`                                      |
| `time_window`       | `[start, end]` với cả 2 đầu mút đều inclusive |
| `cost` trong output | cost nội bộ dùng cho objective optimization   |
| `task`              | có thể là `job`, `pickup` hoặc `delivery`     |

---

## Mục lục

- [1. Request Overview](#1-request-overview)
- [2. Jobs](#2-jobs)
- [3. Shipments](#3-shipments)
- [4. Vehicles](#4-vehicles)
- [5. Matrices](#5-matrices)
- [6. Response Overview](#6-response-overview)
- [7. Summary](#7-summary)
- [8. Routes và Steps](#8-routes-và-steps)
- [9. Violations](#9-violations)
- [10. Error Responses](#10-error-responses)
- [11. Ví dụ Request/Response](#11-ví-dụ-requestresponse)
- [12. TypeScript Helper](#12-typescript-helper)

---

# 1. Request Overview

Request body là JSON object mô tả bài toán tối ưu.

| Key         | Required | Type         | Mô tả                                |
| ----------- | -------- | ------------ | ------------------------------------ |
| `jobs`      | No       | `job[]`      | Danh sách điểm giao việc độc lập.    |
| `shipments` | No       | `shipment[]` | Danh sách cặp pickup-delivery.       |
| `vehicles`  | **Yes**  | `vehicle[]`  | Danh sách xe khả dụng để tối ưu.     |
| `matrices`  | No       | `object`     | Custom matrices theo từng `profile`. |
| `matrix`    | No       | `number[][]` | Legacy field đã deprecated.          |

### Ví dụ request tối thiểu

```json
{
  "jobs": [
    {
      "id": 1,
      "location": [106.70098, 10.77689],
      "service": 300
    }
  ],
  "vehicles": [
    {
      "id": 1,
      "start": [106.66017, 10.76262],
      "end": [106.66017, 10.76262]
    }
  ]
}
```

### Validation cơ bản

- `vehicles` phải có ít nhất 1 phần tử
- `id` của `job` không được trùng nhau
- `pickup.id` và `delivery.id` trong shipments không được trùng nhau cùng loại
- nếu dùng custom matrices thì phải khai báo `*_index` tương ứng
- nếu không dùng custom matrices thì phải khai báo tọa độ thật qua `location`, `start`, `end`

---

# 2. Jobs

`job` mô tả một điểm công việc độc lập cần được một xe ghé qua.

| Field              | Required | Type            | Mô tả                                                           |
| ------------------ | -------- | --------------- | --------------------------------------------------------------- |
| `id`               | **Yes**  | `integer`       | ID duy nhất của job.                                            |
| `description`      | No       | `string`        | Mô tả job.                                                      |
| `location`         | Cond.    | `[lon, lat]`    | Tọa độ job. Bắt buộc nếu không dùng custom matrix.              |
| `location_index`   | Cond.    | `integer`       | Index dòng/cột trong custom matrices. Bắt buộc nếu dùng matrix. |
| `setup`            | No       | `integer`       | Thời gian setup, mặc định `0`.                                  |
| `service`          | No       | `integer`       | Thời gian phục vụ, mặc định `0`.                                |
| `setup_per_type`   | No       | `object`        | Map theo `vehicle.type` để override `setup`.                    |
| `service_per_type` | No       | `object`        | Map theo `vehicle.type` để override `service`.                  |
| `delivery`         | No       | `integer[]`     | Nhu cầu delivery đa chiều.                                      |
| `pickup`           | No       | `integer[]`     | Nhu cầu pickup đa chiều.                                        |
| `skills`           | No       | `integer[]`     | Tập kỹ năng bắt buộc.                                           |
| `priority`         | No       | `integer`       | Mức ưu tiên từ `0` đến `100`, mặc định `0`.                     |
| `time_windows`     | No       | `time_window[]` | Các khoảng thời gian hợp lệ để bắt đầu service.                 |

### Ví dụ `job`

```json
{
  "id": 101,
  "description": "Giao hồ sơ chi nhánh A",
  "location": [106.70098, 10.77689],
  "setup": 60,
  "service": 300,
  "delivery": [1],
  "skills": [2, 7],
  "priority": 80,
  "time_windows": [[1713402000, 1713405600]]
}
```

### Ghi chú

- `setup` chỉ áp dụng khi xe vừa đến một location mới
- nếu nhiều task liên tiếp xảy ra cùng vị trí, task sau chỉ tính `service`
- `skills` của job phải là tập con của `skills` xe

---

# 3. Shipments

`shipment` mô tả một cặp công việc có thứ tự bắt buộc: pickup trước, delivery sau.

| Field      | Required | Type            | Mô tả                            |
| ---------- | -------- | --------------- | -------------------------------- |
| `pickup`   | **Yes**  | `shipment_step` | Điểm lấy hàng.                   |
| `delivery` | **Yes**  | `shipment_step` | Điểm giao hàng.                  |
| `amount`   | No       | `integer[]`     | Tải trọng đa chiều của shipment. |
| `skills`   | No       | `integer[]`     | Kỹ năng bắt buộc.                |
| `priority` | No       | `integer`       | Mức ưu tiên `0..100`.            |

## 3.1 Shipment Step

| Field              | Required | Type            | Mô tả                           |
| ------------------ | -------- | --------------- | ------------------------------- |
| `id`               | **Yes**  | `integer`       | ID của step.                    |
| `description`      | No       | `string`        | Mô tả step.                     |
| `location`         | Cond.    | `[lon, lat]`    | Tọa độ step.                    |
| `location_index`   | Cond.    | `integer`       | Chỉ số matrix tương ứng.        |
| `setup`            | No       | `integer`       | Setup duration, mặc định `0`.   |
| `service`          | No       | `integer`       | Service duration, mặc định `0`. |
| `setup_per_type`   | No       | `object`        | Override setup theo loại xe.    |
| `service_per_type` | No       | `object`        | Override service theo loại xe.  |
| `time_windows`     | No       | `time_window[]` | Các slot thời gian hợp lệ.      |

### Ví dụ `shipment`

```json
{
  "pickup": {
    "id": 201,
    "location": [106.66017, 10.76262],
    "service": 180
  },
  "delivery": {
    "id": 202,
    "location": [106.70098, 10.77689],
    "service": 240
  },
  "amount": [5],
  "skills": [3],
  "priority": 90
}
```

### Ghi chú

- backend sẽ báo lỗi nếu `delivery` xuất hiện trước `pickup`
- `shipment` phù hợp với bài toán lấy hàng - giao hàng có ràng buộc precedence

---

# 4. Vehicles

`vehicle` mô tả nguồn lực có thể dùng để phục vụ jobs/shipments.

| Field             | Required | Type             | Mô tả                                                              |
| ----------------- | -------- | ---------------- | ------------------------------------------------------------------ |
| `id`              | **Yes**  | `integer`        | ID xe.                                                             |
| `profile`         | No       | `string`         | Routing profile: `car` \| `truck` \| `motorcycle`, mặc định `car`. |
| `description`     | No       | `string`         | Mô tả xe.                                                          |
| `start`           | Cond.    | `[lon, lat]`     | Điểm xuất phát.                                                    |
| `start_index`     | Cond.    | `integer`        | Index trong matrix cho `start`.                                    |
| `end`             | Cond.    | `[lon, lat]`     | Điểm kết thúc.                                                     |
| `end_index`       | Cond.    | `integer`        | Index trong matrix cho `end`.                                      |
| `capacity`        | No       | `integer[]`      | Tải trọng đa chiều.                                                |
| `costs`           | No       | `cost`           | Chi phí vận hành xe.                                               |
| `skills`          | No       | `integer[]`      | Tập kỹ năng của xe.                                                |
| `type`            | No       | `string`         | Loại xe.                                                           |
| `time_window`     | No       | `time_window`    | Giờ làm việc hợp lệ.                                               |
| `breaks`          | No       | `break[]`        | Danh sách điểm nghỉ.                                               |
| `speed_factor`    | No       | `number`         | Hệ số nhân cho travel time, `(0, 5]`.                              |
| `max_tasks`       | No       | `integer`        | Số task tối đa.                                                    |
| `max_travel_time` | No       | `integer`        | Travel time tối đa.                                                |
| `max_distance`    | No       | `integer`        | Quãng đường tối đa.                                                |
| `steps`           | No       | `vehicle_step[]` | Route custom cho plan mode hoặc starting solution.                 |

## 4.1 Cost Object

| Field           | Required | Type      | Default | Mô tả                                            |
| --------------- | -------- | --------- | ------- | ------------------------------------------------ |
| `fixed`         | No       | `integer` | `0`     | Chi phí cố định nếu xe được dùng.                |
| `per_hour`      | No       | `integer` | `3600`  | Chi phí cho 1 giờ di chuyển.                     |
| `per_task_hour` | No       | `integer` | `0`     | Chi phí cho 1 giờ task time (`setup + service`). |
| `per_km`        | No       | `integer` | `0`     | Chi phí cho 1 km di chuyển.                      |

> Nếu dùng `per_hour` khác mặc định, không nên đồng thời dùng custom cost matrix cho cùng vehicle vì contract gốc xem đó là không nhất quán.

## 4.2 Break Object

| Field          | Required | Type            | Mô tả                                  |
| -------------- | -------- | --------------- | -------------------------------------- |
| `id`           | **Yes**  | `integer`       | ID break trong xe.                     |
| `time_windows` | No       | `time_window[]` | Slot hợp lệ để bắt đầu nghỉ.           |
| `service`      | No       | `integer`       | Thời gian nghỉ.                        |
| `description`  | No       | `string`        | Mô tả break.                           |
| `max_load`     | No       | `integer[]`     | Load tối đa cho phép khi break xảy ra. |

## 4.3 Vehicle Step

| Field            | Required | Type      | Mô tả                                                   |
| ---------------- | -------- | --------- | ------------------------------------------------------- |
| `type`           | **Yes**  | `string`  | `start`, `job`, `pickup`, `delivery`, `break`, `end`.   |
| `id`             | Cond.    | `integer` | ID task/break nếu `type` không phải `start` hoặc `end`. |
| `service_at`     | No       | `integer` | Hard constraint cho thời điểm service.                  |
| `service_after`  | No       | `integer` | Lower bound cho service time.                           |
| `service_before` | No       | `integer` | Upper bound cho service time.                           |

### Ví dụ `vehicle`

```json
{
  "id": 1,
  "profile": "car",
  "description": "Xe tải 1.5 tấn",
  "start": [106.66017, 10.76262],
  "end": [106.66017, 10.76262],
  "capacity": [20],
  "skills": [2, 3, 7],
  "time_window": [1713398400, 1713430800],
  "costs": {
    "fixed": 100000,
    "per_hour": 3600,
    "per_km": 1500
  },
  "breaks": [
    {
      "id": 1,
      "time_windows": [[1713412800, 1713416400]],
      "service": 1800,
      "description": "Nghỉ trưa"
    }
  ]
}
```

### Ghi chú

- `start` và `end` là optional miễn là có ít nhất một trong hai
- nếu bỏ `end`, route kết thúc ở task cuối cùng được phục vụ
- nếu bỏ `start`, route bắt đầu ở task đầu tiên được gán
- nếu `start` và `end` giống nhau, đó là round trip

---

# 5. Matrices

`matrices` cho phép truyền custom matrices theo từng `profile` của xe.

| Key         | Type         | Mô tả                                                     |
| ----------- | ------------ | --------------------------------------------------------- |
| `durations` | `number[][]` | Travel-time matrix dùng cho timing constraints.           |
| `distances` | `number[][]` | Distance matrix. Muốn dùng field này phải có `durations`. |
| `costs`     | `number[][]` | Cost matrix cho objective evaluation.                     |

### Ví dụ

```json
{
  "matrices": {
    "car": {
      "durations": [
        [0, 14],
        [21, 0]
      ]
    },
    "bike": {
      "durations": [
        [0, 57],
        [43, 0]
      ]
    }
  }
}
```

### Ghi chú

- nếu có đủ custom matrices cho mọi `profile` liên quan thì `location`, `start`, `end` có thể bỏ qua
- khi đó cần dùng `location_index`, `start_index`, `end_index`
- nếu có `durations` nhưng không có `distances`, backend vẫn có thể cần truy xuất distance riêng nếu bài toán yêu cầu

---

# 6. Response Overview

Response trả về JSON object mô tả kết quả tối ưu.

| Key          | Type       | Mô tả                                              |
| ------------ | ---------- | -------------------------------------------------- |
| `code`       | `integer`  | Trạng thái xử lý. `0` là thành công.               |
| `error`      | `string`   | Thông báo lỗi nếu `code != 0`.                     |
| `summary`    | `object`   | Tổng hợp chỉ số toàn cục của solution.             |
| `unassigned` | `object[]` | Danh sách task không được gán route, kèm `reason`. |
| `routes`     | `route[]`  | Danh sách route tối ưu.                            |

## 6.1 Status Code

| Code | Ý nghĩa                   |
| ---- | ------------------------- |
| `0`  | Thành công, không có lỗi. |
| `1`  | Internal error.           |
| `2`  | Input error.              |
| `3`  | Routing error.            |

---

# 7. Summary

`summary` là phần tổng hợp của toàn bộ nghiệm.

| Field             | Type          | Mô tả                                          |
| ----------------- | ------------- | ---------------------------------------------- |
| `cost`            | `integer`     | Tổng cost của tất cả routes.                   |
| `routes`          | `integer`     | Số route được tạo.                             |
| `unassigned`      | `integer`     | Số task không được phục vụ.                    |
| `setup`           | `integer`     | Tổng setup time.                               |
| `service`         | `integer`     | Tổng service time.                             |
| `duration`        | `integer`     | Tổng travel time.                              |
| `waiting_time`    | `integer`     | Tổng waiting time.                             |
| `priority`        | `integer`     | Tổng priority của task đã được gán.            |
| `violations`      | `violation[]` | Vi phạm ở cấp solution/route.                  |
| `delivery`        | `integer[]`   | Tổng delivery.                                 |
| `pickup`          | `integer[]`   | Tổng pickup.                                   |
| `distance`        | `integer`     | Tổng khoảng cách, nếu backend có trả distance. |
| `computing_times` | `object`      | Thước đo thời gian xử lý nội bộ của engine.    |

### computing_times

| Field     | Type      | Mô tả                              |
| --------- | --------- | ---------------------------------- |
| `loading` | `integer` | Thời gian load dữ liệu (ms).       |
| `solving` | `integer` | Thời gian giải bài toán (ms).      |
| `routing` | `integer` | Thời gian gọi routing engine (ms). |

---

# 8. Routes và Steps

## 8.1 Route Object

| Field          | Type          | Mô tả                                       |
| -------------- | ------------- | ------------------------------------------- |
| `vehicle`      | `integer`     | ID xe được gán route.                       |
| `steps`        | `step[]`      | Các bước trong route.                       |
| `cost`         | `integer`     | Cost của route.                             |
| `setup`        | `integer`     | Tổng setup time của route.                  |
| `service`      | `integer`     | Tổng service time của route.                |
| `duration`     | `integer`     | Tổng travel time của route.                 |
| `waiting_time` | `integer`     | Tổng waiting time của route.                |
| `priority`     | `integer`     | Tổng priority của task trong route.         |
| `violations`   | `violation[]` | Vi phạm của route.                          |
| `delivery`     | `integer[]`   | Delivery load của route.                    |
| `pickup`       | `integer[]`   | Pickup load của route.                      |
| `description`  | `string`      | Vehicle description nếu có trong input.     |
| `geometry`     | `string`      | Polyline encoded, nếu backend bật geometry. |
| `distance`     | `integer`     | Tổng quãng đường route.                     |

## 8.2 Step Object

| Field            | Type          | Mô tả                                                 |
| ---------------- | ------------- | ----------------------------------------------------- |
| `type`           | `string`      | `start`, `job`, `pickup`, `delivery`, `break`, `end`. |
| `arrival`        | `integer`     | ETA tại step.                                         |
| `duration`       | `integer`     | Travel time tích lũy đến step này.                    |
| `setup`          | `integer`     | Setup time tại step.                                  |
| `service`        | `integer`     | Service time tại step.                                |
| `waiting_time`   | `integer`     | Waiting time trước khi bắt đầu service.               |
| `violations`     | `violation[]` | Vi phạm phát sinh tại step.                           |
| `description`    | `string`      | Mô tả step, nếu có từ input.                          |
| `location`       | `[lon, lat]`  | Tọa độ step, nếu input có cung cấp.                   |
| `location_index` | `integer`     | Index matrix, nếu có.                                 |
| `id`             | `integer`     | ID task/break tương ứng.                              |
| `load`           | `integer[]`   | Tải trọng xe sau khi hoàn tất step.                   |
| `distance`       | `integer`     | Quãng đường tích lũy đến step.                        |

### Ghi chú về `steps`

- trong solving mode, route sẽ được backend tối ưu tự động
- trong plan mode, `vehicle.steps` mô tả route dự kiến và backend chủ yếu tính ETA/violations
- trong solving mode, nếu truyền `vehicle.steps`, đó được xem như starting solution và phải hợp lệ với mọi constraint

---

# 9. Violations

`violation` mô tả một ràng buộc bị vi phạm.

| Field      | Type      | Mô tả                                               |
| ---------- | --------- | --------------------------------------------------- |
| `cause`    | `string`  | Nguyên nhân vi phạm.                                |
| `duration` | `integer` | Mức lệch thời gian nếu là `lead_time` hoặc `delay`. |

## 9.1 Các giá trị `cause`

| Cause             | Ý nghĩa                                                |
| ----------------- | ------------------------------------------------------ |
| `delay`           | Service bắt đầu muộn hơn time window cho phép.         |
| `lead_time`       | Service bắt đầu sớm hơn time window cho phép.          |
| `load`            | Tải trọng vượt capacity.                               |
| `max_tasks`       | Số task vượt `max_tasks`.                              |
| `skills`          | Xe không có đủ skills.                                 |
| `precedence`      | Delivery xảy ra trước pickup hoặc thiếu cặp tương ứng. |
| `missing_break`   | Bỏ qua break bắt buộc trong custom route.              |
| `max_travel_time` | Vượt travel time tối đa.                               |
| `max_distance`    | Vượt distance tối đa.                                  |
| `max_load`        | Load tại thời điểm break vượt `max_load`.              |

> Trong regular optimization, `violations` thường rỗng. Chúng có ý nghĩa rõ nhất khi backend chạy theo logic plan mode để kiểm tra route có sẵn.

---

# 10. Error Responses

### HTTP 400 — Input lỗi (OptimizeApi validation)

```json
{
  "error": "INPUT_ERROR",
  "message": "Request body is empty",
  "code": 2
}
```

```json
{
  "error": "INPUT_ERROR",
  "message": "Request body is not valid JSON",
  "code": 2
}
```

### HTTP 401 — Unauthorized

Thiếu hoặc sai `X-API-Key`.

```json
// (no body — ASP.NET default 401)
```

### HTTP 400/500 — Engine error (forwarded)

Khi engine trả lỗi, OptimizeApi forward nguyên:

```json
{
  "code": 2,
  "error": "Invalid jobs: location missing for job 3."
}
```

| `code` | Ý nghĩa                |
| ------ | ---------------------- |
| `0`    | OK                     |
| `1`    | Internal error         |
| `2`    | Input validation error |

### Unassigned jobs

Khi có job không giao được, response sẽ chứa mảng `unassigned` kèm lý do:

```json
{
  "unassigned": [
    {
      "id": 5,
      "type": "job",
      "location": [106.72, 10.75],
      "reason": "No vehicle with matching skills"
    }
  ]
}
```

---

# 11. Ví dụ Request/Response

## 11.1 Ví dụ Request

### Bài toán 1 xe, 3 điểm giao

```bash
curl -X POST https://live.fleetwork.vn/api/v1/optimize \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicles": [
      {
        "id": 1,
        "profile": "car",
        "start": [106.6297, 10.8231],
        "end": [106.6297, 10.8231]
      }
    ],
    "jobs": [
      { "id": 1, "location": [106.6602, 10.7626], "service": 300 },
      { "id": 2, "location": [106.7010, 10.7769], "service": 300 },
      { "id": 3, "location": [106.6893, 10.8018], "service": 180 }
    ]
  }'
```

### Ví dụ loại service (theo thời gian phục vụ)

Quy ước ví dụ:

- `service: 120` -\> giao nhanh (2 phút)
- `service: 300` -\> giao tiêu chuẩn (5 phút)
- `service: 900` -\> giao cồng kềnh (15 phút)

```bash
curl -X POST https://live.fleetwork.vn/api/v1/optimize \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicles": [
      {
        "id": 1,
        "profile": "car",
        "start": [106.6297, 10.8231],
        "end": [106.6297, 10.8231]
      }
    ],
    "jobs": [
      { "id": 101, "location": [106.6602, 10.7626], "service": 120 },
      { "id": 102, "location": [106.7010, 10.7769], "service": 300 },
      { "id": 103, "location": [106.6893, 10.8018], "service": 900 }
    ]
  }'
```

## 11.2 Ví dụ Response `200 OK`

```json
{
  "code": 0,
  "summary": {
    "cost": 3600,
    "unassigned": 0,
    "delivery": [0],
    "pickup": [0],
    "service": 300,
    "duration": 3300,
    "waiting_time": 0,
    "distance": 12500,
    "priority": 0,
    "violations": [],
    "computing_times": {
      "loading": 2,
      "solving": 45,
      "routing": 10
    }
  },
  "unassigned": [],
  "routes": [
    {
      "vehicle": 1,
      "cost": 3600,
      "service": 300,
      "duration": 3300,
      "waiting_time": 0,
      "distance": 12500,
      "priority": 0,
      "violations": [],
      "delivery": [0],
      "pickup": [0],
      "steps": [
        {
          "type": "start",
          "location": [106.6297, 10.8231],
          "arrival": 0,
          "duration": 0,
          "distance": 0
        },
        {
          "type": "job",
          "id": 1,
          "location": [106.701, 10.7769],
          "arrival": 2800,
          "duration": 3300,
          "distance": 12500,
          "load": [0]
        },
        {
          "type": "end",
          "location": [106.6297, 10.8231],
          "arrival": 3600,
          "duration": 3600,
          "distance": 15200
        }
      ]
    }
  ]
}
```

---

## Lưu ý triển khai

- nếu bài toán có ràng buộc tải trọng, hãy khai báo đồng nhất giữa `vehicle.capacity`, `job.delivery` / `job.pickup`, hoặc `shipment.amount`
- nếu backend trả về distance hoặc geometry, cần có cấu hình tương ứng ở lớp routing engine
- nếu dùng timestamp tuyệt đối trong `time_window`, các giá trị `arrival` trong output cũng được hiểu là timestamp tuyệt đối
- nếu dùng giá trị tương đối, toàn bộ `arrival` sẽ là thời gian tương đối theo planning horizon
- engine forward nguyên response — không bọc thêm wrapper
- timeout khuyến nghị cho bài toán lớn là **5 phút**
