You are on page 1of 8

ĐỀ THI THỬ MDE CUỐI KỲ NGÀY 19/07/2022

THỜI GIAN 90 PHÚT


Câu 1 (3 điểm):
Một chương trình nhận dạng xâu tin nhắn để dự đoán kết quả bóng đá. Giả sử các đội chia làm 3 bảng
A, B, C với các trận như sau

Trận Bảng A Bảng B Bảng C

1 Malaysia-Brunei Myanma-Viet Thai-Phy

2 Malaysia-Indo Viet-Timor Thai-Sing

3 Indo-Brunei Timor-Cam Sing-Phy

4 Brunei-Lao Myanma-Cam

5 Lao-Indo Myanma-Timor

6 Lao-Malaysia Cam-Viet

Người dùng được phép nhắn tin đến đầu số để dự đoán kết quả trận đấu. Tin nhắn có nội dung tên
bảng, theo sau là tên trận đấu, tiếp theo là chữ cái đầu của đội sẽ thắng. Nếu dự đoán hai đội hoà thì sẽ
là không có chữ cái đầu của đội nào cả.
Chẳng hạn
“A 1 M”. Tin nhắn này mang nghĩa dự đoán đội Malaysia sẽ thắng trong trận Malaysia-Brunei của
bảng A
“B 5” , tin nhắn này mang nghĩa dự đoán cả hai đội sẽ hoà trong trận Myanma-Timor
a) Hãy vẽ biểu đồ trạng thái đoán nhận nội dung đúng định dạng của tin nhắn (2 điểm)
Ta xác định các trạng thái
S0: trạng thái bắt đầu, hay còn gọi là trạng thái chờ bảng đấu.
+ S0 nếu đọc được ký tự space (khoảng trắng) thì vẫn ở trạng thái S0
+ S0 nếu gặp các ký tự khác A, B, C sẽ chuyển sang trạng thái S2 (trạng thái lỗi)
+ S0 nếu gặp các ký tự như là A, hoặc B, hoặc C sẽ chuyển sang trạng thái S1
S1: trạng thái đã biết bảng đấu, đang chờ đợi dấu cách
+ S1 nếu gặp ký tự khác space (khoảng trắng) thì chuyển sang trạng thái S2
+ S1 nếu gặp space (khoảng trắng) thì chuyển sang trạng thái S3
S2: trạng thái lỗi, chờ khoảng trắng để bắt đầu một quá trình đoán nhận mới
+ S2 nếu gặp space (khoảng trắng) thì chuyển sang trạng thái S0
+ Ngược lại, S2 sẽ vẫn ở trạng thái S2
S3: trạng thái chờ thông số trận đấu
+ S3 nếu gặp space thì vẫn ở trạng thái S3
+ S3 nếu gặp con số phù hợp (1-6 với bảng A, B; còn 1-3 với bảng C) thì chuyển sang trạng thái
S4
+ S3 nếu gặp A hoặc B hoặc C thì chuyển sang trạng thái S1
+ S3 nếu gặp ký tự không phù hợp (<1 hoặc > 6 với bảng A, hoặc < 1 hoặc > 3 với bảng C,
hoặc các ký tự chữ cái còn lại) thì chuyển sang trạng thái S2
S4: đã biết thông số bảng đấu và trận đấu, chờ khoảng trắng
+ nếu không gặp ký tự kết thúc câu (dấu phẩy, dấu chấm, dấu “, dấu chấm than…) ngoại trừ
space thì chuyển sang trạng thái S7
+ Nếu gặp ký tự chữ cái hoặc chữ số thì chuyển sang trạng thái S2
+ nếu gặp space thì chuyển sang trạng thái S5
S5: chờ tên đội thắng
+ S5 nếu gặp ký tự là chữ cái biểu thị tên đội thắng có trong bảng thì chuyển sang trạng thái chờ
kết thúc S6.
+ S5 nếu gặp C mà bảng đấu có đội C thì chuyển sang trạng thái S6
+ S5 nếu gặp C mà bảng đấu không có đội C thì chuyển sang trạng thái S1
+ S5 nếu gặp A, B thì chuyển sang trạng thái S1
+ S5 nếu gặp space thì vẫn ở trạng thái S5
+ Ngược lại thì chuyển sang trạng thái S2
S6: chờ kết thúc
+ S6 nếu gặp ký tự là chữ cái thì chuyển sang trạng thái S2
+ S6 nếu gặp ký tự khác chữ cái thì chuyển sang trạng thái S7
S7: với mọi ký tự, vẫn ở trạng thái S7
Ở đây ta có 3 trạng thái kết thúc: S7, S6, S5, S4

b) Xây dựng mã nguồn cài đặt biểu đồ trạng thái kể trên (1 điểm)
//Ở đây em viết space để đại diện cho ký tự khoảng trắng
public class S0 {
public S0 getNext(char c){
if(c == space) return this;
if(c == ‘A' || c == ‘B || c == ‘C’)
return new S1(c);
return new S2( );
}
public void show( ) { Sysout(“Wrong"); }
}

public class S1 extends S0{


private char table;
public S1(char c)
{
table = c;
}
public char getTable( ) { return table; }
public S0 getNext(char c){
if(c == space) return new S3(table);
return new S2( );
}
}
public class S2 extends S0{
public S0 getNext(char c)
{
if(c != space) return this;
return new S0( );
}
}
public class S3 extends S1{
public S3(char c)
{
super(c);
}
public S0 getNext(char c){
if( (c >= ‘1’ && c <= ‘6’ && (c == ‘A’ || c == ‘B’))
|| (c >= ‘1’ && c <= ‘3’ && c == ‘C’)
)
{
return new S4(getTable( ), c);
}
else{
if(c >= ‘A’ &&| c <= ‘C’)
return new S4(getTable( ), c);
if(c == space) return new S3( );
}
return new S2( );
}
}
public class S4 extends S3{
private char match;
public char getMatch( ) { return match; }
public S4(char table, char match)
{
super(table);
this.match = match;
}
private String endedChars = “\”;.,?/\|}][{+=-_)(*&^%$#@!~`:”;
public S0 getNext(char c){
if(endedChars.contains(c))
{
return new S7( );
}
if(c == space) return new S5(getTable( ), match);
return new S2( );
}
}
public class S5 extends S4{
public S5(char table, char match)
{ super(table, match); }
public S0 getNext(char c)
{
switch(getTable( ) )
{
case ‘A’:
switch(getMatch( ))
{
case ‘1’: if(c == ‘B’) return new S6( );
if(c == ‘I') return new S2( );
case ‘2’: if(c == ‘I' || c == ‘M') return new S6( );
return new S2( );
case ‘3’: if(c == ‘I') return new S

}
}
}

Câu 2 (1 điểm)
Theo em phương pháp phát triển phần mềm hướng mô hình có áp dụng cho ngôn ngữ C được không?
Tại sao?
Gợi ý: Phương pháp phát triển phần mềm hướng mô hình áp dụng cho nhóm ngôn ngữ nào?
Ngôn ngữ C có thuộc nhóm ngôn ngữ đó không?

Câu 3 (6 điểm)
Một hệ thống lọc email (Filter) trao đổi giữa các nhân viên và khách hàng. Mỗi người đó có một tài
khoản trên hệ thống với các thông tin: tên (name), tuổi (age), tên email (email), số căn cước công dân
(pid). Nhân viên (Employee) có thêm thông số định danh nhân viên (eid), cấp bậc (level kiểu int).
Khách hàng (Customer) có thêm thông tin mã khách hàng (cid) và doanh thu từ khách hàng đó
(income kiểu double). Còn có một loại tài khoản nữa là tài khoản không nhận tin phản hồi (NoReply),
tài khoản này chỉ có thuộc tính mang tên là email.
Khi một thông điệp được gửi từ người này đến người khác, thông điệp đó có một người gửi (sender)
và ít nhất một người nhận (rec). Mỗi thông điệp có thông số về tiêu đề (title), nội dung (content), thời
điểm gửi (time kiểu long).
Hệ thống lọc email sẽ tiến hành kiểm tra thông điệp với phương thức check nhận đầu vào là thông
điệp và trả về true nếu thông điệp kia là hợp lệ (không phải spam). Phương thức classify trong hệ
thống lọc sẽ nhận đầu vào là thông điệp, rồi trả về đối tượng của lớp Employee hoặc Customer nếu
phía gửi mail là con người và họ gửi thông điệp không hợp lệ. Phương thức đó trả về null ở các
trường hợp còn lại. Hệ thống lọc mail này còn có phương thức getNotifier, nhận đầu vào là mảng các
thông điệp, và trả về một đối tượng kiểu NoReply hoặc Employee. Mảng này đại diện cho các đối
tượng được trao quyền gửi các tin nhắn chúc mừng ngày lễ đến khách hàng.
a) Vẽ biểu đồ lớp (3 điểm)
b) Đặc tả các yêu cầu: trong số các sender và rec của một thông điệp bất kỳ thì phải có ít nhất một
người là nhân viên (0.5 điểm)
Một người chỉ được gửi tối đa cho 50 người khác một lúc (0.5 điểm)
Nếu trong số người nhận có khách hàng, thì các nhân viên trong danh sách người nhận (nếu có) phải
cùng level. (0.5 điểm)
Nếu thông điệp từ NoReply gửi cho khách hàng thì khách hàng không được lớn hơn 50 tuổi (0.5
điểm).
Đáp án:
context Message
inv: self.sender.oclIsKindOf(Employee) or self.rec->exists(r | r.oclIsKindOf(Employee) )
inv: self.rec->exists(r | r.oclIsKindOf(Customer) ) implies self.rec->forAll(c1, c2 |
c1.oclIsKindOf(Employee) and c2.oclIsKindOf(Employee)
implies c1.oclAsType(Employee).level == c2.oclAsType(Employee).level )
c) Cài đặt mã nguồn phương thức getNotifier với các bước cài đặt như sau.
- Lọc ra các thông điệp hợp lệ (không phải spam) có người gửi là Customer (0.25 điểm)
- Tìm kiếm xem trong số các thông điệp hợp lệ của đầu vào, có thông điệp nào được đối
tượng NonReply gửi không (0.25 điểm)
- Nếu dưới 1/3 số thông điệp hợp lệ là được gửi bởi Customer và tìm được đối tượng
NonReply ở ý trên, thì phương thức sẽ trả về đối tượng này (0.25 điểm)
- Ngược lại thì chọn ngẫu nhiên ra một nhân viên trong số người nhận sao cho level của người
này lớn hơn trung bình level của các nhân viên có trong danh sách người nhận (0.25 điểm)
- Trả về đối tượng nhân viên này
Gợi ý: giả sử hệ thống đã cài đặt sẵn phương thức getRandomIndex(int min, int max) trả về một số
nguyên ngẫu nhiên trong đoạn [min, max]
public INotifier getNotifier(Message m[ ]){
Vector<Message> v = new Vector<Message>( );
for(int i = 0; i < m.length; i++)
{
if(check(m[i]) && m[i].getSender( ) instanceof Customer){
v.add(m[i]);
}
}
NonReply n = null;
int count = 0; int L = 0;
Vector<Employee> es = new Vector<Employee> ( );
for(int i = 0; i < v.size( ); i++)
{
if(v[i].getSender( ) instanceof NonReply)
{
n = v[i].getSender( );
}
for(int j = 0; j < v[i].getRec( ).size( ); j++)
{
if(v[i].getRec( )[j] instanceof Employee)
{
if(!es.contains(v[i].getRec( )[j]))
{
es.add(v[i].getRec( )[j]);
count++;
L += (Employee)(v[i].getRec( )[j]).lvl;
}
}
}
}
if(v.size( ) < m.length/3 && n != null) return n;
else{
if(es.size( ) != 0)
{
double avg = (double)L/count;
Vector<Employee> largerAvg = new Vector<Employee> ( );
for(int i = 0; i < es.size( ); i++)
{
if(es[i].level > avg)
largerAvg.add(es[i]);
}
int index = getRandomIndex(0, largerAvg.size()-1);
return largerAvg[index];
}
}
return null;

}
Họ và tên:..............................................................
MSSV:...................................

Họ và tên:..............................................................
MSSV:...................................

Họ và tên:..............................................................
MSSV:...................................

You might also like