Bài toán chúc Tết

Chúc tết

Bài toán chúc Tết

Một người quyết định dành một ngày Tết để đến chúc Tết các bạn của mình. Để chắc chắn, hôm trước anh ta đã điện thoại đến từng người để hỏi khoảng thời gian mà người đó có thể tiếp mình. Giả sử có N người được hỏi (đánh số từ 1 đến N), người thứ i cho biết thời gian có thể tiếp trong ngày là từ Ai đến Bi (i = 1, 2, …, N). Giả thiết rằng, khoảng thời gian cần thiết cho mỗi cuộc gặp là H và khoảng thời gian chuẩn bị từ một cuộc gặp đến một cuộc gặp kế tiếp là T. Bạn hãy xây dựng giúp một lịch chúc Tết để anh ta có thể chúc Tết được nhiều người nhất.

File dữ liệu vào trong file CHUCTET.INP gồm dòng đầu ghi số N, dòng thứ i trong số N dòng tiếp theo ghi khoảng thời gian có thể tiếp khách của người i gồm 2 số thực Ai và Bi (cách nhau ít nhất một dấu trắng). Dòng tiếp theo ghi giá trị H (số thực) và dòng cuối cùng ghi giá trị T (số thực). Giả thiết rằng các giá trị thời gian đều được viết dưới dạng thập phân theo đơn vị giờ, tính đến 1 số lẻ (thí dụ 10.5 có nghĩa là m­ời giờ r­ỡi) và đều nằm trong khoảng từ 8 đến 21 (từ 8 giờ sáng đến 9 giờ tối). Số khách tối đa không quá 30.

Kết quả ghi ra file CHUCTET.OUT gồm dòng đầu ghi K là số người được thăm, K dòng tiếp theo ghi trình tự đi thăm, mỗi dòng gồm 2 số (ghi cách nhau ít nhất một dấu trắng): số đầu là số hiệu người được thăm, số tiếp theo là thời điểm gặp tương ứng.

Thí dụ:

CHUCTET.INP                               

20                                                                           

10.5 12.6

15.5 16.6

14.0 14.1

17.5 21.0

15.0 16.1

10.5 10.6

19.0 21.0

10.5 13.6

12.5 12.6

11.5 13.6

12.5 15.6

16.0 18.1

13.5 14.6

12.5 17.6

13.0 13.1

18.5 21.0

 9.0 13.1

10.5 11.6

10.5 12.6

18.0 21.0

 0.5

 0.1

CHUCTET.OUT

16

17   9.0

 1  10.5

18  11.1

19  11.7

  8  12.3

10  12.9

11  13.5

13  14.1

  5  15.0

  2  15.6

12  16.2

14  16.8

  4  17.5

  7  19.0

16  19.6

20  20.2

Thuật toán

Để giải quyết bài toán này, ta có thể sử dụng giải thuật tham lam (greedy algorithm). Ý tưởng là ta sẽ thăm các người có thể tiếp sớm nhất và kết thúc sớm nhất. Ta sẽ duyệt qua danh sách các người cần chúc Tết, sau đó sắp xếp lại danh sách đó theo thời gian bắt đầu gặp mỗi người. Tiếp theo, ta bắt đầu từ người đầu tiên và duyệt qua danh sách các người còn lại, lần lượt chọn các người có thể tiếp sớm nhất và kết thúc sớm nhất.

Để tính thời gian có thể tiếp mỗi người, ta cần lưu giữ thời gian bắt đầu tiếp người trước đó. Với mỗi người, nếu thời gian bắt đầu có thể tiếp trễ hơn thời gian kết thúc tiếp người trước đó, ta sẽ đặt thời gian bắt đầu tiếp người này bằng thời gian kết thúc tiếp người trước đó. Nếu thời gian bắt đầu tiếp người này vẫn còn trễ hơn thời gian có thể tiếp, ta sẽ bỏ qua người này và chuyển sang người kế tiếp.

Sau khi thăm hết tất cả các người, ta sẽ thu được danh sách các người đã được thăm theo thứ tự và thời điểm được thăm. Kết quả này sẽ được ghi ra file CHUCTET.OUT.

Cài đặt bài toán với Python

# Mở file input để đọc dữ liệu
with open("CHUCTET.INP", "r") as f:
    # Đọc số lượng người cần chúc Tết
    n = int(f.readline().strip())
    # Khởi tạo một list chứa thông tin thời gian của từng người
    a_b = []
    # Đọc dữ liệu về thời gian của từng người và lưu vào list a_b
    for i in range(n):
        ai, bi = map(float, f.readline().strip().split())
        a_b.append((ai, bi))
    # Đọc dữ liệu về khoảng thời gian cần thiết cho mỗi cuộc gặp và khoảng thời gian chuẩn bị
    h = float(f.readline().strip())
    t = float(f.readline().strip())

# Sắp xếp các người theo thời gian bắt đầu tiếp khách
# Sử dụng lambda function để lấy giá trị thời gian bắt đầu tiếp khách của mỗi người
a_b.sort(key=lambda x: x[0])

# Khởi tạo các biến lưu trữ thông tin lịch chúc Tết
result = []
last_end_time = 8.0  # Thời điểm bắt đầu đi chúc Tết là 8 giờ sáng

# Duyệt qua từng người để xây dựng lịch chúc Tết
for i in range(n):
    # Lấy thông tin thời gian của người thứ i
    ai, bi = a_b[i]
    # Tính thời điểm kết thúc tiếp khách của người trước đó
    last_end_time += t + h
    # Nếu thời gian bắt đầu tiếp khách của người hiện tại còn trước thời điểm kết thúc tiếp khách của người trước đó
    # thì cần đợi cho đến thời điểm kết thúc tiếp khách của người trước đó
    if ai < last_end_time:
        waiting_time = last_end_time - ai
        ai += waiting_time
        bi += waiting_time
    # Thêm thông tin lịch chúc Tết của người hiện tại vào kết quả
    result.append((i+1, ai))
    # Cập nhật thời điểm kết thúc tiếp khách của người trước đó
    last_end_time = bi

# Ghi kết quả ra file output
with open("CHUCTET.OUT", "w") as f:
    f.write(str(len(result)) + "\n")
    for r in result:
        f.write(str(r[0]) + " " + str(r[1]) + "\n")

Cài đặt bài toán với C++

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct TimeSlot {
    double start, end;
};

bool operator<(const TimeSlot& a, const TimeSlot& b) {
    return a.start < b.start;
}

int main() {
    int n;
    cin >> n;
    vector<TimeSlot> timeSlots(n);
    for (int i = 0; i < n; i++) {
        cin >> timeSlots[i].start >> timeSlots[i].end;
    }
    double H, T;
    cin >> H >> T;
    
    sort(timeSlots.begin(), timeSlots.end());
    
    vector<pair<int, double>> schedule;
    double lastEnd = -1e9; // thời điểm cuối cùng đã tiếp khách
    for (int i = 0; i < n; i++) {
        // nếu thời gian bắt đầu của khoảng tiếp khách hiện tại lớn hơn thời điểm cuối cùng đã tiếp khách
        if (timeSlots[i].start >= lastEnd + T) {
            schedule.push_back({i+1, timeSlots[i].start});
            lastEnd = timeSlots[i].start + H;
        }
    }
    
    sort(schedule.begin(), schedule.end(), [](auto a, auto b) {
        return a.second < b.second;
    });
    
    cout << schedule.size() << endl;
    for (auto s : schedule) {
        cout << s.first << " " << s.second << endl;
    }
    return 0;
}

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *