Tải bản đầy đủ (.doc) (63 trang)

Đề và đáp án kỳ thi cao học môn Kỹ thuật lập trình PTIT

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (350.5 KB, 63 trang )

-1HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG
CƠ SỞ TP. HỒ CHÍ MINH

ĐỀ VÀ ĐÁP ÁN KỲ THI TUYỂN SINH CAO HỌC
MÔN THI
: KỸ THUẬT LẬP TRÌNH
THỜI GIAN
: 180 PHÚT
Đề 1
Câu 1. Cho trước số tự nhiên N. Hãy tìm tất cả các ước số nguyên tố của nó .
Đáp án:
#include <stdio.h>
#include <conio.h>
void main () {
int n ;
printf ("n=") ; scanf ("%d", &n);
int j=0; int i=2;
while (n >1)
{ while (n %i !=0 ) i++;
if (i !=j) { printf ("%8d", i); j =i ; }
n = n/i;
}
getch();
}

(1đ)

Câu 2. Cho trước mảng 1 chiều. Hãy viết lại mảng sao cho tất cả các phần tử khác
không nằm ở đầu mảng, các phần tử bằng không ở cuối mảng và vẫn giữ nguyên trật
tự trước sau của các phần tử khác không, không được thiết lập 1 mảng mới.
(1đ)


Đáp án:
- Thuật toán :
+ Duyệt dãy và chuyển các phần tử khác không về đầu dãy
+ Điền 0 vào các phần tử còn lại
- Chương trình :
void TachDay(int A[], int n) {
int i; int j=-1;
for (i = 0 ; i < n; i++)
if (A[i] !=0)
{ j++;
if (i != j ) { A[j] = A[i]; A[i] =0; }
}
}

(0.25)

(0.75)


-2Câu 3. Giả sử ta có 20000 số nguyên phân biệt khác nhau (các số nguyên đó có trò từ
1..30000) trong 1 file text Dayso.txt.
(3đ)
a. Hãy trình bày cách lưu trữ và thuật toán sắp xếp dãy trên theo thứ tự tăng dần sao
cho ít tốn bộ nhớ trong nhất và sắp xếp nhanh nhất.
(1đ)
b. Cài đặt thuật toán đã trình bày ở câu a.
(1đ)
c. Viết chương trình con liệt kê dãy đã được sắp ra màn hình.
(1đ)
Đáp án :

a. Vì các số nguyên phân biệt khác nhau và có miền giá trò từ 1 đến 30000 nên ta chọn
phương án lưu trữ 1 số nguyên trên 1 bit, và số bytes cần thiết để lưu trữ 20000 số
nguyên này là 30000/8 = 3750 bytes. Do đó, ta đã giảm 40000 bytes xuống còn 3750
bytes. Ta quy ước cách lưu trữ số nguyên trên bit như sau : (các bit được đánh số từ 0
đến 7 tính từ trái qua)
(1đ)
1 0 0 0 1 1 1 1 * 1 0 1 0 1 1 1 1* …..* ……
Nếu số nguyên = 1 thì ta bật bit thứ 0 của byte 0
Nếu số nguyên = 5 thì ta bật bit thứ 4 của byte 0
………
Nếu số nguyên = 11 thì ta bật bit thứ 2 của byte 1
Với cách quy ước này thì rõ ràng sau khi ta đã lưu 20000 số vào 3750 bytes thì dãy đã
có thứ tự tăng dần, nên thời gian sắp xếp dãy là bằng 0.
Ghi chú: Dấu * là dấu hiệu cho ta biết qua byte kế tiếp
b. / Chương trình con :
const int MAX = 32000;
const SO_BYTE = MAX/8;
unsigned char A[SO_BYTE];
void TaoDay(unsigned char A[])
{
int so;
int byte, bit;
unsigned char mask [8] = {0x80,0x40,0x20,0x10,8,4,2,1};
for (int i=0; iFILE *f;
if ((f=fopen("dayso.txt","r"))==NULL)
{ printf ("Loi mo file\n"); exit (0) ;
}
while (!feof(f))
{fscanf(f, "%d", &so);

byte = so / 8; bit = so % 8;

(1đ)


-3if ( (A[byte] & mask[bit]) == 0)
{
printf("%8d",so) ; A[byte]= A[byte] | mask[bit];
}
}
}
c. void Lietke(unsigned char A[])
{ unsigned int mask = 0x80;
printf("\n SO DA DUOC SAP :\n");
for (int i=0; i{ mask = 0x80;
for (int j=0; j<8 ; j++)
{ if (( A[i] & mask) == mask)
printf("%8d", i*8+j);
mask = mask >> 1;
}
}
}

(1đ)

Câu 4. Ta có 1 hệ thống cho phép người dùng truy nhập đến 1 điểm bất kỳ trong 2000
điểm trên 1 bản đồ bằng cách chạm vào tấm nhập liệu (input pad). Các vò trí trên bản
đồ được biểu diễn bằng các tọa độ (cột x, dòng y), trong đó x là số nguyên nằm trong
khoảng 1..200, và y là số nguyên nằm trong khoảng 1..150 . Trong chương trình,

người ta biểu diễn bản đồ bằng mảng 2 chiều [200][150] số nguyên (các số nguyên
đó có giá trò từ 1..2000 hoặc bằng 0 nếu không có điểm nào của bản đồ tại vò trí ấy).
Góc dưới bên trái của bảng này có dạng sau, trong đó các ô trống chỉ giá trò 0.
6
5
4
3
2
1

538
965
1121
17
98
1

2

162
3

4

8

Với cách lưu trữ như vậy thì rõ ràng thời gian để xác đònh điểm nào (trong số 2000
điểm) được lưu trữ tại vò trí (i,j) nhanh nhưng sẽ tốn bộ nhớ (chiếm 200 * 150 =
30000 từ 16 bits).



-4a. Bạn hãy đưa ra 1 cách thức lưu trữ 2000 điểm trên sao cho ít tốn bộ nhớ hơn.
Viết khai báo và chương trình con để lưu trữ 1 điểm x tại vò trí (i,j) trong bản
đồ. (1.5đ)
b. Viết chương trình con để xác đònh điểm nào (trong số 2000 điểm) được lưu
trữ tại vò trí (cot i,dong j) theo cách thức lưu trữ mà bạn đề nghò trong câu a.
Nếu không có điểm nào được lưu trữ tại vò trí (i,j) thì chương trình con sẽ trả
về 0.
(1.5đ)
Đáp án:
a. Ta sử dụng 3 mảng sau:
(1đ)
int FirstInCol [201] ; // FirstInCol [i+1]- FirstInCol [i] cho biết có bao nhiêu điểm trên
bản đồ nằm trên cột i và điểm đầu tiên ở tọa độ (cột, dòng) = (i, Row[FirstInCol[i]])
int Value [2000] : chứa giá trò điểm
int Row [2000]
: chứa vò trí dòng của điểm có cột thuộc FirstInCol
Value
Row

17
3

538
6

1053
127

98

2

15
139

1800
12

FirstInCol

1
4
6
6
199
201
1
2
3
4

Các điểm trong cột I được biểu diễn bằng các phần tử trong mảng Row và Value giữa
các vò trí FirstInCol[I] và FirstInCol[I+1]-1. Theo hình trên, ta có 3 điểm trong cột thứ
nhất : điểm 17 ở vò trí (1,3) , điểm 538 ở vò trí (1,6) và điểm 1053 ở vò trí (1,127). Có 2
điểm trong cột 2: điểm 98 ở vò trí (2,2) , điểm 15 ở vò trí (2,139) . Cột 3 không có điểm
nào. Như vậy, với cách lưu trữ này ta sẽ tốn 4201 từ 16 bits.
Cài đặt:
(0.5đ)
b. Để xác đònh giá trò 1 điểm được lưu tại vò trí (cot i, dong j), ta có đoạn mã sau:
for (int k = FirstInCol[i] ; k <=FirstInCol[i+1]-1; k++)

(1.5đ)
if (Row[k]=j then return Value[k];
return 0;

Câu 5. Cho 1 vector A chứa n số thực [1..n]. Ta đònh nghóa vector con của A la ø là
vector mà thành phần của nó là các thành phần liên tiếp trong A (vector rỗng có thể
xem là vector con của A). Ta gọi tổng của 1 vector là tổng của tất cả các thành phần
của nó. Trình bày thuật toán và viết chương trình con để xác đònh tổng lớn nhất trong
tất cả các tổng của các vector con của A với bậc cao nhất O(n) = n; biết rằng vector
con lớn nhất≥ 0
(2đ)
Đáp án:


-5long Tong_Vecto_con(int A[], int n)
{ long max=0;
long MaxEnd=0;
for (int i=1 ; i<=n; i++)
{
if (MaxEnd+A[i] > 0)
MaxEnd= MaxEnd+A[i] ;
else MaxEnd=0
if ( max < MaxEnd)

max =MaxEnd;

}
return max;
}
- HẾT –



-6-

HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG
CƠ SỞ TP. HỒ CHÍ MINH

ĐỀ VÀ ĐÁP ÁN KỲ THI TUYỂN SINH CAO HỌC
MÔN THI
: KỸ THUẬT LẬP TRÌNH
THỜI GIAN
: 180 PHÚT
Đề 2
Câu 1. Trong mảng A[1:n] (với n khá lớn) chỉ chứa các số 0,1, và 2. Hốn vị các phần tử
của mảng, sao cho đầu mảng chứa các số 1, sau đó là các số 2, cuối mảng là các số 0.
Lưu ý : Khơng được dùng mảng phụ.


-7Đáp án:
void Cau1(int *A , int n) {
int B [3] ;
B[0] = B[1]=B[2] = 0;
/* B[0] chua so cac so 0
B[1] chua so cac so 1
B[2] chua so cac so 2
*/
// Dem so cac so 1, 2 va 0
for ( i=1; i<=n; i++)
B[A[i]] = B[A[i]]+1;
for ( i=1 ; i<=B[1] ; i++) A[i]=1 ;

for ( i=1 ; i<=B[2] ; i++) A[B[1]+i]=2 ;
for ( i=1 ; i<=B[0] ; i++) A[ B[1]+B[2]+i]=0 ;
}
Câu 2. Một mảng chứa N cặp số thực (ai, bi) tương ứng với N đường thẳng yi = aix+bi.
Các đường được sắp xếp theo đoạn [0,1] trên trục x với ý nghóa sau: y itrò i giữa 0 và N-2, và với mọi giá trò của x trên đoạn [0,1]:

0

1

Trình bày thuật toán và viết chương trình con để xác đònh nhanh 2 đường gần nhất
“bao quanh” điểm P(xP,yP) , với P là điểm cho trước và 0 ≤ xP ≤ 1.
Đáp án :
1. Thuật toán:
- Giả sử ta khai báo DuongThang A[N] để A chứa N đường thẳng của đề bài, (xp, yp)
là tọa độ của điểm P.
const N=100;
typedef struct DuongThang {
float a, b;
};

DuongThang A[N]
Để tìm nhanh 2 đường gần nhất bao quanh điểm P(xP,yP) , với P là điểm cho
trước và 0 ≤ xP ≤ 1, ta kẻ 1 đường thẳng song song với trục tung và cắt trục hoành


-8tại điểm xP, đường thẳng này sẽ cắt N đường thẳng trong dãy A tại N vò trí. Do tính
chất yip dụng thuật toán tìm nhò phân để tìm y P trên dãy Y tăng dần, ta sẽ có kết quả

của đề bài.
Kết quả : có 4 trường hợp nghiệm :
Nếu P nằm ngay trên 1 đường thẳng Y[i] thì trả về i
Nếu yP < Y0 : trả về 0
Nếu yP < YN-1 : trả về N-1
Nếu P không thỏa 3 trường hợp trên thì trả về i , i+1 với Y[i] < y P < Y[i+1]
Câu 3. Cho trước 1 dãy khóa A[1:n] thuộc kiểu số ngun. Hãy trình bày cách thức lưu
trữ và thuật tốn để có thể tìm nhanh 1 khóa k có trong dãy khóa hay khơng ?
Lưu ý: Dãy chưa được sắp thứ tự
Đáp án: Ta dùng hàm băm A[i] % 101 với phương pháp nối kết trực tiếp để lưu trữ dãy
khóa này.
const M = 101 ;
typedef struct node {
int key; // khóa
int dc ; // đòa chỉ của khóa key trong A
struct node * next ;
};
typedef struct node * ref;
ref heads [M]
Bước 1: Khởi tạo bảng băm: cho các đòa chỉ đầu của các dslk trong heads về NULL.


-9Bước 2: Chuyển các khóa vào mảng băm:
for (int i=0; iInsert_First(A[i], i, A[i] % M]
Bước 3: Tìm kiếm 1 khóa k trong bảng băm: nếu tìm thấy thì hàm sẽ trả về đ/c của
phần tử chứa khóa, nếu không tìm thấy thì trả về -1
int Search (int k, ref heads[]) {
int h = k % M;
ref p= heads[h];

for ( ; p !=NULL && p->node.key <> k ; p = p->next) ;
if ( p==NULL ) return -1;
else return p->node.dc;
}
Câu 4. Cho trước mảng 2 chiều A[1:n][1:n], mỗi phần tử của nó bằng 0, 1, 5 hoặc 11.
Hãy tính số lượng các bộ bốn A[i,j], A[i+1,j], A[i, j+1], A[i+1, j+1] trong đó các phần tử
đều khác nhau.


- 10
Đáp án: Duyệt mảng 2 chiều, với mỗi i,j ta so sánh
if (A[i ][j]+ A[i+1][j]+ A[i] [j+1]+ A[i+1][ j+1]==17) dem ++;
Câu 5. Cho1 đồ thò G có hướng. Đồ thò có tối đa MAX đỉnh. Các đỉnh được đánh số từ
0 đến n –1, với n là số đỉnh thực tế của đồ thò (0 < n ≤ MAX)
a. Viết khai báo để lưu trữ đồ thò G trên theo cấu trúc ma trận kề.
b. Viết chương trình con để xác đònh đồ thò có đường đi từ đỉnh u đến đỉnh v hay
không?
Đáp án
a) Khai báo để lưu trữ 1 đồ thò G có hướng có trọng số theo cấu trúc ma trận kề
const MAX = 50; // Số đỉnh tối đa của đồ thò
typedef int Dothi[MAX][MAX] ;
Dothi G ;
int n ; // số đỉnh thực tế trong G;
b) Chương trình con xác đònh đồ thò có đường đi từ đỉnh u đến đỉnh v hay không
Thuật toán:
- Ta dùng thuật toán WarShall để tìm bao đóng BD của của đồ thò G .
- Nếu trong mảng 2 chiều BD mà BD [u][v] != 0 nghóa là sẽ có 1 đường đi từ đỉnh
u đến đỉnh v, và ngược lại.
Chương trình:
void WarShall( int G[][MAX], int n, int u, int v)

{
int i,j,k, dem;
int C[MAX][MAX], P[MAX][MAX];
int BD[MAX][MAX]; // bao dong cua ma tran G
for( i=0; ifor (j=0;jBD[i][j]= P[i][j]=G[i][j];
for ( dem=1; dem{
for ( i=0; ifor (j=0; j< n;j++)
{
C[i][j]=0;


- 11
for (k=0; k}
for (i=0;ifor (j=0 ; j{
P[i][j]=C[i][j];
BD[i][j]=BD[i][j] || P[i][j]; // don ma tran P vua tinh vao bao dong
}
} // for ñem
// Kieåm tra BD[u][v]
if (BD[u][v] !=0)
cout << “Co duong di tu dinh “ << u << “den dinh “ << v ;
else cout << “Khong co duong di tu dinh “ << u << “den dinh “ << v;
}

- HẾT -


- 12
-

HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG
CƠ SỞ TP. HỒ CHÍ MINH

MÔN THI
THỜI GIAN

ĐỀ VÀ ĐÁP ÁN KỲ THI TUYỂN SINH CAO HỌC
: KỸ THUẬT LẬP TRÌNH
: 180 PHÚT
Đề 3

Câu 1: Hãy cho biết kết quả thực hiện của chương trình dưới đây.
#include <stdio.h>
#include <conio.h>
#include <string.h>

char str[255]="AB1 AB2 AB3 AB4 AB5 AB6 AB7 AB8 AB9 AC1 AC2 AC3 AC4 AC5 AC6 \

AC7 AC8 AC9 AD1 AD2 AD3 AD4 AD5 AD6 AD7";
void main(void){
int n, m=0, k=0;n = strlen(str);char s[32];
for(int i=0; i<=n; i++){
switch(str[i]){
case ' ' :

case '\t':
case '\n':
case '\r':
case '\0':
if (k>0) {
s[k]='\0';m++;k=0;
printf("\n Ket qua buoc %d:%s",m,s);
}
break;
default:
s[k++]=str[i]; break;
}
}
}

Câu 2: Cho dãy gồm n số tự nhiên phân biệt a1, a2, .., an (n ≤ 1000); và hai số tự nhiên k (kvà B. Hãy liệt kê tất cả các dãy con k phần tử của dãy số {an} sao cho tổng các phần tử của dãy
con đó đúng bằng B. Dữ liệu vào cho bởi file Data.in theo khn dạng như sau:
• Dòng đầu tiên ghi lại các số tự nhiên n, k và B. Hai số khác nhau được viết cách nhau bởi
một vài ký tự trống.
• Dòng kế tiếp ghi lại n số ngun dương a1, a2,..,an. Hai số khác nhau được viết cách nhau
bởi một vài ký tự trống.


- 13
Các dãy con k phần tử tìm được ghi lại trong file Ketqua.out theo khuôn dạng sau:
• Dòng đầu tiên ghi lại một số tự nhiên m là số các dãy con k phần tử của dãy {an} có tổng
các phần tử đúng bằng B.
• m dòng tiếp ghi lại trên mỗi dòng là một dãy con k phần tử của dãy {an} có tổng các phần
tử đúng bằng B. Hai phần tử khác nhau của dãy con được viết cách nhau bởi một vài

khoảng trống.
Ví dụ : Với file Data.in dưới đây sẽ cho ta file Ketqua.out tương ứng.

Data.in
7
5

3 50
10 15

Ketqua.out
20

25

30 35

4
10
5
5
5

15
20
15
10

25
25

30
35

Câu 3: Ta định nghĩa một từ là dãy các kí tự không chứa khoảng trống (space), dấu tab, dấu
xuống dòng (‘\n’), dấu về đầu dòng (‘\r’) và dấu kết thúc dòng (‘\0’). Cho hai file văn bản
Data1.in và Data2.in.
Hãy tìm tập các từ xuất hiện trong file Data1.in nhưng không xuất hiện trong file Data2.in.
Các từ tìm được ghi lại trong file Ketqua.out theo khuôn dạng sau:
• Dòng đầu tiên ghi lại số tự nhiên k là số từ xuất hiện trong file Data1.in nhưng không xuất
hiện trong file Data2.in;
• k dòng kế tiếp, mỗi dòng ghi lại một từ xuất hiện trong file Data1.in nhưng không xuất
hiện trong file Data2.in.
Ví dụ dưới đây sẽ minh họa cho các file dữ liệu vào và file kết quả của bài toán.
Data1.in
AB AC AD AE AF AG AH
AB CD CF CE AF AG AH

Data2.in
AB AC AD AI CA CB
CD CE CF CG

Ketqua.out
4
AE
AF
AG
AH

Câu 4: Cho một danh sách liên kết với con trỏ đầu là First nhằm quản lý danh sách các
sinh viên trong một trường. Mỗi sinh viên có các thông tin sau đây: masv (mã sinh viên tối đa 8 ký tự), ho (họ - tối đa 40 ký tự), ten (tên - tối đa 10 ký tự), gt (giới tính - tối đa

3 ký tự), malop (mã lớp - tối đa 8 ký tự) và được khai báo theo kiểu cấu trúc:
typedef struct SINHVIEN {
char masv [8]; char ho [40];
char ten[10]; char gt [3] ; char malop [8];
};
typedef struct node {
SINHVIEN sv;
struct node *next;
} ;
typedef struct node *PTR;


PTR First;

- 14
-

a. Viết chương trình con tạo một danh sách chứa các phần tử, mỗi phần tử chứa
thông tin sau: masv (mã sinh viên) của một sinh viên trong danh sách liên kết
First, diachi (địa chỉ) chứa địa chỉ vùng nhớ tương ứng với sinh viên có mã
masv trong danh sách sinh viên.
b. Viết chương trình con sắp xếp danh sách sinh viên tăng dần theo mã sinh viên
masv sao cho ta có thể đưa danh sách sinh viên mới sắp xếp này quay trở lại trật
tự ban đầu như khi nhập liệu.
Câu 5: Cho đồ thị vô hướng G có n đỉnh với các đỉnh được đánh số từ 1 đến n theo cấu trúc ma
trận kề sau đây:
const MAX = 50; // Số đỉnh tối đa của đồ thị
typedef int Dothi[MAX][MAX] ;
Dothi G ;
int n; // số đỉnh của đồ thị G


Hãy viết chương trình con để xác định đồ thị G có đường đi từ đỉnh u đến đỉnh v hay không?
Ghi chú: Cán bộ coi thi không giải thích gì thêm
ĐÁP ÁN

NỘI DUNG
Câu 1. Tách chuỗi thành các từ
- AB1 , AB2, AB3, AB4, AB5, AB6
- AB7, AB8, AB9, AC1, AC2, AC3
- AC4, AC5, AC6, AC7, AC8, AC9, AD1, AD2
- AD3, AD4, AD5, AD6, AD7
Câu 2.
- Đọc dữ liệu đúng khuôn dạng
int n, k, w,B[100], A[100], count=0, OK=1;FILE *fp;
void Init(void){
fp=fopen("DATA.IN","r");
fscanf(fp,"%d %d %d",&n, &k, &w);
printf("\n n=%d k=%d w= %d:",n, k, w);
printf("\n Day so:");
for(int i=1; i<=n; i++){
fscanf(fp,"%d",&A[i]);
B[i]=0;
printf("%5d",A[i]);
}
fclose(fp);
}
- Xác định 1 dãy con
void Next_Bit_String(void){
int i=n;


ĐIỂM
2,0
0.5đ
0.5đ
0.5đ
0.5đ

0.25đ

0.5đ


- 15
while(i>0 && B[i]) { B[i]=0; i--;};
if(i>0) B[i]=1;
else OK=0;
}
- Tính tổng dãy con, xác định dãy con thỏa điều kiện, ghi kết quả theo đúng khuôn
dạng
void Result(void){
int s=0;
int sopt_daycon=0;
for(int i=1; i<=n; i++){
s = s + A[i]*B[i];
if (B[i]) sopt_daycon++;
}
if ((sopt_daycon ==k) && (s==w)){
count++; printf("\n Ket qua %d:",count);
fprintf(fp,"\n");
for(i=1; i<=n; i++){

if(B[i]){
printf("%3d",A[i]);
fprintf(fp,"%5d",A[i]);
}
}
}
}
void Duyet(void){
clrscr();Init();
fp=fopen("Ketqua.out","w");
while(OK){
Result();
Next_Bit_String();
}
rewind(fp);
fprintf(fp,"%d\n",count);
fclose(fp);
}
Câu 3:
- Tách và tìm số từ của toàn bộ file Data1.In , Data2.In
typedef char w[20];
FILE *fp1,*fp2;
char name1_inp[12]="DATA1.IN", name2_inp[12]="DATA2.IN";
char name1_out[12]="KETQUA.OUT";
int wf1, wf2, wf3, k;
w tu1[1000], tu2[1000];
int Find_Word( w *tu, int wn, w temp){
for(int i=1; i<=wn; i++){
if(strcmp(temp, tu[i])==0)
return(i);

}

0.25đ
0.25đ

0.25đ

0.5đ

2.0đ

0.5đ


- 16
return(i);
}
int Tim_Tap_Tu(char *name, w tu[] ){
w temp; char s[20];
fp1 = fopen(name,"r");
int wn=0;
while(!feof(fp1)){
fscanf(fp1,"%s",s);
k = Find_Word(tu,wn,s);
if(k>wn) { wn++; strcpy(tu[wn],s); }

0.5đ

}
fclose(fp1); return(wn);

}
- Tìm tập hiệu các từ và ghi kết quả đúng khuôn dạng
int Find_Word_File1_In_File2(char *s, w *tu, int n){
for(int i=1; i<=n; i++){
if(strcmp(s, tu[i])==0)
return(1);
}
return(0);
}
void TapHieu(void){
int i; wf3=0;
fp1=fopen("Ketqua.out","w");
fprintf(fp1,"\n
");
printf("\nHieu = \n");
for(i=1; i<=wf1; i++){
if (Find_Word_File1_In_File2(tu1[i],tu2, wf2)==0){
wf3++;
printf("\n %s", tu1[i]);
fprintf(fp1,"\n %s",tu1[i]);
}
}
rewind(fp1);
fprintf(fp1,"%d",wf3);
fclose(fp1);
}
void main(void){
clrscr();
wf1 = Tim_Tap_Tu(name1_inp, tu1);
wf2 = Tim_Tap_Tu(name2_inp, tu2);

TapHieu();
printf("\n Ket thuc");
getch();
}

Câu 4:
typedef

0.5đ
0.25đ

0.25đ

2.0đ

struct SINHVIEN {


char
char
char
char
char

masv [8];
ho [40];
ten[10];
gt [3] ;
malop [8];


- 17
-

};
typedef struct node {
SINHVIEN sv;
struct node *next;
} ;
typedef struct node *PTR;
PTR First;
a. typedef struct PhanTu {
char masv[8];
PTR diachi ;
};
PhanTu * Index ;
int n ;
void Tao_Index (PTR First, PhanTu *Index, int &n) {
PTR p;
for ( p= First, n=0 ; p <> NULL; p=p->next) n++ ;
Index = new PhanTu [n];
for ( int i=0, p=First ; p <> NULL ; p= p->next, i++)
{ strcpy(Index[i].masv, p->sv.masv);
Index[i].diachi = p;
}
}
b.
- Sắp xếp dãy Index tăng dần trên masv theo 1 thuật toán Sort

0.25đ


0.25đ
0.25đ
0.25đ


Câu 5:
const MAX = 50;
// Số đỉnh tối đa của đồ thị
typedef int Dothi[MAX][MAX] ;
Dothi G ;
int n; // số đỉnh của đồ thị G
Hãy viết chương trình con để xác định đồ thị G có đường đi từ đỉnh u đến đỉnh v
hay khơng?
Thuật tốn:
Ta dùng thuật tốn DFS duyệt đồ thị từ đỉnh u, trong q trình duyệt nếu tìm
thấy đỉnh v thì trả về 1 . Nếu kết thúc DFS mà vẫn khơng thấy v thì trả về 0 .
int DFS(Dothi G, int n, int u, int v)

2.0đ


- 18
{
int *C = new int [n+1] ;
int *Stack= new int [n] ;

// de danh dau cac dinh da di qua
// Stack de chua cac dinh trong khi

duyet

int sp ;
int i,x ;
for (i=1; i<=n; C[i++] =0 );
sp=0;
// khoi tao Stack
Stack[sp]=u;
C[u]=1 ;
// da duyet qua dinh u
while (sp >-1)
{
x=Stack[sp];
sp-- ;
// xoa dinh vua tham ra khoi Stack
if (x==v) return 1;
for (i=1; i <= n; i++)
// dua tat ca cac nut chua duyet tu x vao C
if (G[x][i] && C[i]==0)
{
Stack[++sp]=i;
C[i]=1;
}
}
return 0;
}

0.25đ

0.25đ

1.5đ



- 19
-

HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG
CƠ SỞ TP. HỒ CHÍ MINH
ĐỀ VÀ ĐÁP ÁN KỲ THI TUYỂN SINH CAO HỌC
MÔN THI
: KỸ THUẬT LẬP TRÌNH

THỜI GIAN

: 180 PHÚT

Đề 4

Câu 1: Hãy cho biết kết quả thực hiện của chương trình dưới đây:
#include <stdio.h>
#include <conio.h>
void main(void){
long k = 123; int d, b = 4, n = 0, count = 0;
char s[32];
do {
d = k % b; k = k/b;
if( d >= 0 && d <= 9)
s[++n] = '0' + d;
else
if (d >= 10 && d <= 36)
s[++n] = 'A' + (d-10);

else
s[++n]= 'a' + (d-26);
printf("\n Ket qua buoc %d:%c", ++count, s[n]);
} while(k!=0);
printf("\n Ket qua buoc %d:",++count);
for(int i=n; i >= 1; i--)
printf("%3c",s[i]);
}

Câu 2: Cho dãy gồm n số tự nhiên phân biệt a1, a2, .., an (n ≤ 1000) và số tự nhiên B . Hãy liệt kê
tất cả các dãy con của dãy số {an} sao cho tổng các phần tử của dãy con đó đúng bằng B. Dữ liệu
vào cho bởi file data.in theo khn dạng như sau:
• Dòng đầu tiên ghi lại hai số tự nhiên n và B. Hai số được viết cách nhau bởi một vài
khoảng trống.




- 20
Dòng kế tiếp ghi lại n số nguyên dương a1, a2,..,an. Hai số khác nhau được viết cách nhau
bởi một vài ký tự trống.

Các dãy con tìm được ghi lại trong file Ketqua.out theo khuôn dạng sau:


Dòng đầu tiên ghi lại số tự nhiên k là số các dãy con của dãy {an} có tổng các phần tử
đúng bằng B.
• k dòng tiếp theo mỗi dòng ghi lại là một dãy con của dãy {an} có tổng các phần tử đúng
bằng B. Hai phần tử khác nhau của dãy con được viết cách nhau bởi một vài khoảng
trống.

Ví dụ với file Data.in dưới đây sẽ cho ta file Ketqua.out tương ứng.

Data.in
7 50
5 10 15 20 25 30 35

Ketqua.out
7
20
15
10
5
5
5
5

30
35
15
20
15
10
10

25
25
30
35
15


20

Câu 3: Một cây nhị phân được gọi là cân bằng hoàn toàn nếu tại tất cả các nút, số nút của
cây con bên trái và số nút của cây con bên phải của nút đó chênh lệch nhau không quá 1.
Cho cây nhị phân tìm kiếm có con trỏ đầu tree chỉ đến gốc của cây với khai báo sau:
struct node {
int key;
int info ;
struct node *left;
struct node *right;
} ;
typedef struct node *PTR;
PTR tree;

a. Hãy viết chương trình con xác định xem cây nhị phân tree có phải là cây nhị phân tìm
kiếm cân bằng hoàn toàn hay không?
b. Hãy viết hàm trả về mức của nút có khóa key = X, với X là số nguyên dương và giả sử
rằng nút gốc có mức bằng 1. Ghi chú là trong trường hợp cây tree không có nút với khóa
X thì hàm sẽ trả về 0.
Câu 4: Ta định nghĩa một từ là dãy các kí tự không chứa khoảng trống (space), dấu tab, dấu
xuống dòng (‘\n’), dấu về đầu dòng (‘\r’) và dấu kết thúc dòng (‘\0’). Tần xuất xuất hiện của từ
N (W )
W trong tập văn bản D, ký hiệu là P(W) và được tính theo công thức: P (W ) =
; trong đó
N ( D)
N(W) là số lần xuất hiện từ W trong văn bản D, N(D) là số từ của văn bản D.
Cho file văn bản Data.in. Hãy tìm tập các từ và tần xuất xuất hiện của mỗi từ trong file văn bản
Data.in. Kết quả các từ và tần xuất xuất hiện của từ tìm được ghi lại trong file Ketqua.out theo
khuôn dạng sau:
• Dòng đầu tiên ghi lại số tự nhiên K là số từ xuất hiện trong file Data.in;

• K dòng kế tiếp, mỗi dòng ghi lại một từ W và tần xuất xuất hiện của từ đó P(W) trong file
Data.in. W và P(W) được viết cách nhau bởi một vài khoảng trống.


- 21
Ví dụ dưới đây sẽ minh họa cho file Data.in và Ketqua.out của bài toán.
Data.in
A

AB

AC

AD

AE

A

AB

AE

AF

Ketqua.out
6
A
AB
AC

AD
AE
AF

0.22
0.22
0.11
0.11
0.22
0.11

Câu 5: Cho đồ thị vô hướng G có n đỉnh với các đỉnh được đánh số từ 1 đến n theo cấu trúc ma
trận kề sau đây:
const MAX = 50; // Số đỉnh tối đa của đồ thị
typedef int Dothi[MAX][MAX] ;
Dothi G ;
int n; // số đỉnh của đồ thị G

Hãy viết chương trình con để xác định đồ thị G có liên thông hay không?

Ghi chú: Cán bộ coi thi không giải thích gì thêm

ĐÁP ÁN

NỘI DUNG
Câu 1. Lấy phần dư của phép chia 4
Ket qua buoc 1: 3
Ket qua buoc 2: 2
Ket qua buoc 3: 3
Ket qua buoc 4: 1

Ket qua buoc 5: 1 3 2 3
Câu 2.
- Đọc dữ liệu đúng khuôn dạng
int n, w,B[100], A[100], count=0, OK=1;FILE *fp;
void Init(void){
fp=fopen("DATA.IN","r");
fscanf(fp,"%d %d",&n, &w);
printf("\n n=%d w= %d:",n, w);
printf("\n Day so:");
for(int i=1; i<=n; i++){
fscanf(fp,"%d",&A[i]);
B[i]=0;
printf("%5d",A[i]);
}
fclose(fp);
}

THANG ĐIỂM
2,0đ
0.5đ
0.5đ
0.5đ
0.5đ

0.25đ


- 22
- Xác định 1 dãy con
void Next_Bit_String(void){

int i=n;
while(i>0 && B[i]) { B[i]=0; i--;};
if(i>0) B[i]=1;
else OK=0;
}
- Tính tổng dãy con, xác định dãy con thỏa điều kiện, ghi kết quả
theo đúng khuôn dạng
void Result(void){
int s=0;
for(int i=1; i<=n; i++){
s = s + A[i]*B[i];
}
if(s==w){
count++; printf("\n Ket qua %d:",count);
fprintf(fp,"\n");
for(i=1; i<=n; i++){
if(B[i]){
printf("%3d",A[i]);
fprintf(fp,"%5d",A[i]);
}
}
}
}
void Duyet(void){
clrscr();Init();
fp=fopen("Ketqua.out","w");
while(OK){
Result();
Next_Bit_String();
}

rewind(fp);
fprintf(fp,"%d\n",count);
fclose(fp);
}
Câu 3.

0.25đ

0.25đ
0.5đ

0.25đ

0.5đ

2,0đ

struct node {
int key;
int info ;
struct node *left;
struct node *right;
} ;
typedef struct node *PTR;

PTR tree;
a. Xác định xem cây nhị phân tree có phải là cây nhị phân
tìm kiếm cân bằng hoàn toàn hay không?
0.25đ



- 23
int SoNut (PTR tree) // tính số nút của cây nhị phân tree
int CanBangHoanToan (PTR treee)
{
const STACKSIZE = 100;
PTR Stack[STACKSIZE];
int cont,sp, trai, phai;
PTR p=tree;
sp=-1; // Khoi tao Stack rong
cont=1;
while (p!=NULL && cont)
{ trai = SoNut (p->left) ;
phai = SoNut (p->right);
if ( abs ( trai-phai) >1) return 0; // không cân bằng hoàn
toàn
if (p->right != NULL)
Stack[++sp]= p->right;
if (p->left != NULL)
p=p->left;
else if (sp==-1)
cont =0;
else
p=Stack[sp--];
}
return 1; // cây nhị phân cân bằng hoàn toàn
}

0.75đ


b. int MucNut(PTR tree, int x ) {
PTR p = tree; int muc =1;
while ( p != NULL && p->key !=x)
{ if ( x < p->key ) p = p ->left;
else p = p->right ;
muc++;
}
return (p ==NULL ? 0 : muc) ;
}
Câu 4:
typedef struct {
char word[20];
int solan;
float tanxuat;
} w;
FILE *fp1;
int wn=0, wf1, wf=0 ; // wf - số từ toàn bộ file
w tu[1000];

0.5đ

void Init(void){
wn=0; wf=0;
}

0.5đ
2.0đ
0.5đ



- 24
- Tách từ trong file và tập hợp lại trong mảng w
int Tim_Tap_Tu( w tu[] ){
w temp; char s[20];
int k;
fp1 = fopen("Data.in","r");
while(!feof(fp1)){
fscanf(fp1,"%s",s); wf++;
strcpy(temp.word, s);
temp.solan=1; temp.tanxuat=0.0;
k = Find_Word(tu,wn,temp);
if(k>wn) {wn++; tu[wn]=temp;}
else tu[k].solan++;
}
fclose(fp1); return(wn);
}

0.5đ

- Tìm từ trong mảng tu[]
// Nếu i//Nếu i=wn+1 thi bổ xung từ mới vào vị trí wn+1
int Find_Word( w *tu, int wn, w temp){
for(int i=1; i<=wn; i++){
if(strcmp(temp.word, tu[i].word)==0)
return(i);
}
return(i);
}
- Tính tần xuất xuất hiện mỗi từ, ghi kết quả đúng khuôn dạng

void In_Tu(w *tu, int k){
printf("\n Ket qua:");
fp1= fopen("Ketqua.Out","w");
fprintf( fp1, "\n%d",wn);
for(int i=1; i<=k;i++){
tu[i].tanxuat = (float) tu[i].solan /(float) wf;
printf("\n %10s %3d %6.2f", tu[i].word, tu[i].solan,
tu[i].tanxuat);
fprintf(fp1, "\n %10s %6.2f", tu[i].word, tu[i].tanxuat);
}
fclose(fp1);
}
void main() {
Init();
wf1 = Tim_Tap_Tu( tu);
In_Tu(tu,wf1);
}
Câu 5:
const MAX = 50;

0.5đ

0.5đ

2.0đ
// Số đỉnh tối đa


- 25
của đồ thị

typedef int Dothi[MAX][MAX] ;
Dothi G ;
int n; // số đỉnh của đồ thị G
Viết chương trình con để xác định đồ thị G có liên thông hay
không?
Thuật toán:
Xét 1 đỉnh u (1..n) trong đồ thi G, ta dùng thuật toán DFS duyệt
đồ thị từ đỉnh u, trong quá trình duyệt nếu phát hiện 1 đỉnh v
không xuất hiện trong kết quả duyệt thì trả về 0 để cho biết đồ
thị không liên thông.
int LienThong(Dothi G, int n)
{
int *C = new int [n+1] ; // de danh dau cac dinh da di qua
int *Stack= new int [n] ; // Stack de chua cac dinh trong
khi duyet
int sp ; int i,x ;
int u=1;
for (i=1; i<=n; C[i++] = 0 );
sp=0;
// khoi tao Stack
Stack[sp]=u;
C[u]=1 ;
// da duyet qua dinh u
while (sp >-1)
{
x=Stack[sp];
sp-- ; // xoa dinh vua tham ra khoi Stack
for (i=1; i <= n; i++) // dua tat ca cac nut chua duyet tu x
// vao C
if (G[x][i] && C[i]==0)

{
Stack[++sp]=i;
C[i]=1;
}
}
for (i=1; i<=n && C[i] ==1 ; i++ );
if (i <=n) return 0;
return 1;
}
Hoặc ta còn có 1 cách giải khác:

0.5đ

0.5đ

0.25đ

0.25đ

0.5đ


×