SPOJ.COM – Thuật toán bài STPAR - Street Parade

28/10/2016 7 minutes read
Share:

Đề bài:

Để đảm bảo rằng chiếc xe diễu hành sẽ hoạt động trở lại vào mùa hè, mỗi năm ban tổ chức quyết định một thứ tự xác định trước cho việc trang trí những chiếc xe. Kinh nghiệm dạy họ rằng nên giữ một cạnh trống để có thể đưa những chiếc xe vào theo đúng thứ tự.

Đường bên cạnh là rất nhỏ. Vì vậy, 2 chiếc xe không thể cùng vượt qua. Do đó, những chiếc xe nào vào sau sẽ phải ra trước. Bởi vì các xe đi rất gần nhau nên chúng không thể quay đầu hay vào trở lại. Bạn được cho thứ tự đến của những chiếc xe. Viết chương trình kiểm tra xem các chiếc xe có thể đi vào theo đúng thứ tự mà ban tổ chức quyết định hay không.

Đầu vào:

Có nhiều test case. Dòng đầu tiên của mỗi test case là một số n, số lượng của những chiếc xe. Dòng thứ 2 chứa các số từ 1 đến n, sắp xếp theo tứ tự ngẫu nhiên. Tất cả các chữ số được phân cách bởi dấu cách. Những số này biểu diễn thứ tự, mà những chiếc xe đi đến con đường. Số xe là không lớn hơn 1000. Kết thúc của đầu vào là số 0.

Đầu ra:

Với mỗi test case , in ra 1 dòng duy nhất là "yes" nếu như thoả mãn, ngược lại thì in ra là "no".

Ví dụ:

Đầu vào:

5
5 1 2 4 3 
0

Đầu ra:

yes

Giải thích:

Ban đầu:

sptar-street-parade-spoj-com-thuattoan-phamvanlam-com-pic-1

Xe có thể thay đổi như sau:

sptar-street-parade-spoj-com-thuattoan-phamvanlam-com-pic-2

sptar-street-parade-spoj-com-thuattoan-phamvanlam-com-pic-3

sptar-street-parade-spoj-com-thuattoan-phamvanlam-com-pic-4

sptar-street-parade-spoj-com-thuattoan-phamvanlam-com-pic-5

Quá trình kết thúc.

Các bạn có thể tham khảo link gốc đề bài và submit code tại đây: http://www.spoj.com/problems/STPAR/

Phân tích:

  • Ở đây, tôi sẽ dùng ngăn xếp stack để giải quyết bài toán. Bài toán này có thể xếp vào dạng sử dụng [thuật toán tham lam Greedy.]/category/tham-lam-greedy/)

Lời giải:

(Các bạn nên tự mình nghĩ ra thuật toán của bài toán trước khi tham khảo code của tôi nhé. Hãy phát huy tối đa khả năng sáng tạo của bản thân. Hơn nữa code tôi viết ra cũng chưa thật sự tối ưu.  Nên rất mong nhận được sự chia sẻ của các bạn.)

Code C/C++:

#include <iostream>
using namespace std;
const int MAX = 1005;
int Order[MAX]; // Thứ tự ban đầu của những chiếc xe
int Stack[MAX]; // Biểu diễn ngăn xếp stack, tương ứng với đoạn đường bên cạnh
int St_size; // Độ dài ngăn xếp
int Check; // Lưu kết quả
int main()
{
//freopen("input.txt","r",stdin);
int N = 0;
while(true)
{
// Nhập đầu vào là số lượng xe
cin >> N;
if(N == 0) break;
for(int i = 0; i < N; i++)
cin >> Order[i];
St_size = 0;
Check = true;
// Chỉ số xe có thể đi, ban đầu có giá trị 1
int start = 1;
// Duyệt từng xe
for(int i = 0; i < N; i++)
{
// Kiểm tra xem nếu đỉnh ngăn xếp có giá trị start thì cho đi
while(St_size > 0 && Stack[St_size-1] == start)
{
St_size--;
start++;
}
// Nếu đầu dãy là start thì cho đi, tăng start lên 1 đơn vị
if(Order[i] == start) start++;
else if (St_size > 0 && Stack[St_size-1] < Order[i])
{
// Nếu trường hợp này xảy ra thì chắc chắn sẽ không thoả mãn.
// Vì trường hợp này ta sẽ phải cho điểm ở đầu dãy vào ngăn xếp
// Mà sau khi cho xong thì tồn tại 1 điểm có giá trị nhỏ hơn
// (ưu tiên cao hơn)
// điểm ở đầu ngăn xếp, mà nó lại không thể đi ra được.
Check = false;
break;
}
else // Cho điểm đầu của dãy vào ngăn xếp.
{
Stack[St_size] = Order[i];
St_size++;
}
}
if(Check) cout << "yes" << endl;
else cout << "no" << endl;
}
return 0;
}
view raw STPAR.cpp hosted with ❤ by GitHub

Code Python:

MAX = 1005
stack = [0] * MAX
while(1):
n = int(raw_input())
if n == 0:
break
order = map(int, raw_input().split())
st_size = 0
check = 1
start = 1
for i in range(0, n):
while (st_size > 0 and stack[st_size - 1] == start):
st_size -= 1
start += 1
if order[i] == start :
start += 1
elif st_size > 0 and stack[st_size - 1] < order[i]:
check = 0
break
else:
stack[st_size] = order[i]
st_size += 1
if check == 1:
print "yes\n"
else:
print "no\n"
view raw STPAR.py hosted with ❤ by GitHub

Code by Phạm Văn Lâm.

Share: