Bài giải kỹ thuật lập trình ôn thi cao học Học viện công nghệ bưu chính viễn thông. Sát đề thi khoảng 80%
Trang 1THUẬT TOÁN TÌM CẠNH CẦU DUYỆT THEO DFS
1 Khai báo biến:
- Mảng chứa ma trận a[max][max]
- Mảng chuaxet[max]= (true-1: chưa xét, false=0: đã xét)
- Biến int dinhke
- Typedef Struct { int u,v;} canh; canh canhcau[max]
2 Các hàm cần viết:
- Hàm input : đọc dữ liệu đầu vào.
- Hàm init_chuaxet: Ban đầu các đỉnh đều gán chuaxet=true;
- Hàm Duyet_DFS(int u)
{ chuaxet[u]=false; //danh dau u tham roi
for (int v=1;v<=n;v++)//xet cac dinh v tu 1 den n
if (chuaxet[v]==true&&a[u][v]==1)//neu v chua tham va v ke u
Duyet_DFS(v);//goi de qui de tham v //tra ve ket qua nhung dinh ke voi dinh duoc xem la tru co nam trong danh sachduong di khong
if (chuaxet[dinhke]==true) //neu van con dinh chua di qua
return false; //tra ve ket qua khong co duong di toi het cac dinh
{ init_chuaxet(); //khoi tao mang chua xet, tat ca cac dinh la chua di
if (a[t][j]==1) //neu j la dinh ke voi t
{
a[t][j]=0; //loai bo canh noi giua 2 dinh
a[j][t]=0;
dinhke=j; //luu vao bien dinh ke
if (Duyet_DFS(t)==false) // neu duyet khong toi het cac dinh
{ canhcau[++m].u=t; //luu 2 dinh tao nen canh cau
- Hàm output: fprintf(fp,"(%d,%d) ",canhcau[i].u,canhcau[i].v);
- Hàm main: int main()
{input(); tim_canh_cau(); output();}
Trang 2THUẬT TOÁN TÌM ĐỈNH TRỤ DUYỆT THEO BFS
1 Khai báo biến:
- Mảng chứa ma trận a[max][max]
- Mảng chuaxet[max]= (true-1: chưa xét, false=0: đã xét)
- Mảng dinhke[max], dinhtru[max] : chứa các đỉnh kề và đỉnh trụ
- Queue[max]: queue chứa các đỉnh kề
- Int sodinh: số đỉnh kề của t
2 Các hàm cần viết:
- Hàm input : đọc dữ liệu đầu vào.
- Hàm init_chuaxet: Ban đầu các đỉnh đều gán chuaxet=true;
- Hàm Duyet_BFS(int t)
{ int dau,cuoi;//bien dau va bien cuoi de quan ly hang doi
dau=cuoi=1;//ban dau hang doi rong
queue[cuoi++]=t; //Dua dinh t vao queue
chuaxet[t]=false;//t da xet roi
while (dau!=cuoi)//Trong khi hang doi con khac rong
{ u=queue[dau++];//lan luot lay cac dinh trong queue ra, dinh u
for (v=1;v<=n;v++) //lan luot xet cac dinh v
if(a[u][v]==true&&chuaxet[v]==true) //neu v ke voi u va chua xet
{
chuaxet[v]=false;// v da xet roi
queue[cuoi++]=v;//dua v vao queue de xet tiep cac dinh ke voi v
}
}
//tra ve ket qua nhung dinh ke voi dinh duoc xem la tru co nam trong danh sachduong di khong
for(i=1;i<=sodinh;i++)//so dinh ke cua t
if (chuaxet[dinhke[i]]==true) //neu van con dinh chua di qua
return false; //tre ve ket qua khong co duong di toi het cac dinh
return true;
}
Trang 3- Hàm tim_dinh_tru()
{
int p; m=0;
for(t=1;t<=n;t++) //duyet dinh t tu 1 den n
{ init_chuaxet(); //tat ca cac dinh la chua di
sodinh=0; //so dinh ke cua t la 0
for (i=1;i<=n;i++)
if (a[t][i]==1) //voi moi dinh ke voi t
{ p=i; //chon lay dinh de duyet kiem tra duong di
dinhke[++sodinh]=i;//luu lai danh sach dinh ke voi t
a[t][i]=0; //loai bo canh noi giua i va t
a[i][t]=0;
}
if (Duyet_BFS(p)==false) //neu dinh ke voi t di toi het cac dinh con lai
dinhtru[++m]=t; //thi t la dinh tru, luu vao mang dinh tru
//phuc hoi lai canh vua bo truoc do
for (i=1;i<=sodinh;i++)//i chay tu 1 den so dinh ke voi t
- Hàm main: int main()
{input(); tim_dinh_tru(); output();}
Trang 4THUẬT TOÁN TÌM CT VÀ ĐĐ HAMILTON TỪ MA TRẬN KỀ
1 Khai báo biến:
- Mảng chứa ma trận a[max][max]
- Mảng tham[max]= (1: thăm rồi; 0: chưa thăm)
- Mảng x[max] : lưu các đỉnh theo thứ tự của chu trình Hamilton
2 Các hàm cần viết:
- Hàm DocFile : đọc dữ liệu đầu vào (ma trận kề)
- Hàm Duyet (int i) : tìm đỉnh tiếp theo trong chu trình Hamilton
{ for(int j=1;j<=n;j++){//xet cac dinh j tu 1 den n
if(tham[j]==0&&a[x[i-1]][j]==1){//neu j chua tham va j ke voi x[i-1]
x[i]=j;//chon j lam dinh thu i trên chu trìnhtham[j]=1;//danh dau dinh j tham roi
if (i==n){//neu da tim du n dinh
if(a[x[n]][x[1]]==1){//neu dinh thu n ke voi dinh thu 1
}else{//neu dinh thu n khong ke voi dinh thu 1
printf("\n%d)DD:",++count);
for(int k=1;k<=n;k++){//in duong di: x[1], ,x[n]
printf("%d ",x[k]);
}}
Trang 5- Hàm void Hamilton(int dxp){
for(int i=1;i<=n;i++) tham[i]=0;//ban dau tat ca cac dinh la chua tham
x[1]=dxp;//dxp la dinh thu nhat
tham[dxp]=1;//danh dau dxp tham roi
Duyet(2);//tim dinh thu 2
THUẬT TOÁN TÌM CT VÀ ĐĐ HAMILTON TỪ DS CẠNH
- Hàm DocFile(): Đọc danh sách cạnh và chuyển thành ma trận kề
{
int i,j ;
FILE *f= fopen("c:/dscanh.in","r");//mo file dscanh de doc
fscanf(f,"%d %d",&n,&m);//doc so dinh la n va so canh la m
for(i=1;i<=m;i++){//chuyen sang ma tran ke
Trang 6THUẬT TOÁN TÌM CT VÀ ĐĐ HAMILTON TỪ DANH SÁCH KỀ
void init()//Khởi tạo ma trận kề
//Dua du lieu tu file dske vao a
char S[81]; char dinhke[5]; j=0; int num; int dinh =0;
while (fgets(S,80,f)!=NULL) // doc het tung dong(toi da 80 ky tu) va dua vao chuoi S{ //viec doc se ket thuc neu den cuoi file thi tra ve gia tri NULL
for ( int i=0; i <=strlen(S); i++) //duyet tu 0 den het chieu dai day S
if (S[i]==' ' || S[i] =='\t' || S[i]=='\n' || S[i]=='\0') //neu ky tu thu i la trang,tab,xuong dong
{ if (j!=0) // neu j#0 ; i la hang, j la cot
{ dinhke[j]='\0'; j=0; num=atoi(dinhke); //doi tu string sang integer a[dinh][num]=1;
} }
else dinhke[j++]=S[i];
dinh++;
}
Trang 7- Queue[max]: queue chứa các đỉnh kề nếu dùng thuật toán BFS
- Int sodinh: số đỉnh kề của t
2 Các hàm cần viết:
- Hàm input
- Hàm init_chuaxet()
- Ham Duyet_DFS hoặc Duyet_BFS()
void Duyet_DFS(int u)//ham tham mot thanh phan lien thong voi dxp la u
{
printf("%d ",u); //tham dinh u
chuaxet[u]=false; //danh dau u tham roi
for (int v=1;v<=n;v++)//xet cac dinh v tu 1 den n
if (chuaxet[v]==true&&a[u][v]==1)//neu v chua tham va v ke u
Duyet_DFS(v);//goi de qui de tham v}
- Hàm tìm thành phần liên thông
void Tim_tp_lien_thong()
{ int stplt=0;
init_chuaxet();
for(int u=1;u<=n;u++) //lan luot xet cac dinh u tu 1 den n
if (chuaxet[u]==true) //neu u chua xet
{
stplt++;
printf("Thanh phan lien thong thu %d \n",stplt);
Duyet_DFS(u); //tham 1 tp lien thong chua dinh u
printf(" \n");
}
}
- Hàm main
Trang 8CHỨNG MINH ĐỒ THỊ LIÊN THÔNG MẠNH HOẶC YẾU
- Ý tưởng: Đưa thêm biến count vào hàm duyệt DFS-BFS để đếm số phần tử của
thành phần liên thông Nếu đồ thị có hướng (n đỉnh), sau khi duyệt đủ n đỉnh đều tìmthấy tplt có n phần tử thì đồ thị liên thông mạnh Nếu đồ thị không liên thông mạnhthì sẽ viết thêm hàm chuyển từ ma trận có hướng thành ma trận vô hướng, sau đóchạy lại hàm Duyệt DFS-BFS, nếu đồ thị liên thông ở cả n đỉnh thì kết luận đồ thiijliên thông yếu
- Hàm tìm thành phần liên thông
void Tim_tp_lien_thong()
{ int stplt=0; k=0;
init_chuaxet();
for(int u=1;u<=n;u++) //lan luot xet cac dinh u tu 1 den n
if (chuaxet[u]==true) //neu u chua xet
{
stplt++;
printf("Thanh phan lien thong thu %d \n",stplt);
count=1; //reset lại số phần tử trong tplt
Duyet_BFS(u); //tham 1 tp lien thong chua dinh u
printf(" \n");
init_chuaxet(); //tra lai trang thai ban dau de xet tplt tiep theo
if (count!=10) //do thi khong lien thong tai dinh u
TÌM CẠNH CẦN BỔ SUNG HOẶC LOẠI BỎ MÀ ĐT VẪN LIÊN THÔNG
- Ý tưởng: Duyệt BFS-DFS, cạnh đã đi qua thì cho giá trị 2 đỉnh đó bằng 2, sau khi
duyệt cạnh nào có a[i][j]=1 thì loại bỏ
+ Mỗi thành phần liên thông tìm được , ta sẽ lưu 1 đỉnh của thành phần liên thông đóvào mảng bosung[stplt] Cứ n số tplth thì sẽ bổ sung n-1 cạnh để đồ thị liên thông
THUẬT TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT DỰA VÀO BẢNG TRƯỚC
- Ý tưởng: Duyệt BFS-DFS(int u) , lưu vào mảng trước truoc[v]=u
- In kết quá: in từ điểm kết thúc đến điểm bắt đầu
i=dkt; printf("%d", i);
Trang 9for ( long i=2;i<=sqrt(k);i++)
if (k%i==0) return 0; //khong phai so nguyen to
return 1; //la so nguyen to
}
int Test_ThuanNghich (long k, int B) {
char s[20], s1[20];
long n;
ltoa(k,s,10); //doi so long k thanh chuoi s voi he co so 10;
strcpy(s1,s); //copy chuoi s sang chuoi s1
strrev(s); //dao nguoc chuoi s
if(strcmp(s,s1)==0) return 1; //neu chuoi s va s1 giong nhau thi tra ve true
s=s+ (k%10) ; //lay chu so cuoi cua k cong don vao s
k=k/10; //tinh lai k bang cach bo chu so cuoi
Trang 10//Khong chua 1 so nao do
int Khong_chua_so_r(long k,int r)
if(nguyen_to(n)) { printf("\n Kết quả bước:%d:%ld",++k,n); OK=0;}
else if (n%i==0){printf("\n Kết quả bước:%d: %d",++k,i); n = n/i;}
else i++;
} while(OK);
}
Trang 11CÁC THUẬT TOÁN XỬ LÝ CHUỖI
//Ham sinh chuoi nhi phan ke tiep
void Next_Bit_String(void){
int i=n; //duyet tu cuoi
while(i>0 && B[i]) //lap khi chua tim thay B[i]==0
{ B[i]=0; //gan cac bit sau la 0
i ;} //giam ve truoc
if(i>0) B[i]=1; //tim thay B[i]=0 nen gan 1 cho B[i]
else OK=0; // khong tim thay B[i]=0, cau hinh cuoi nen dung
count++; printf("\n Ket qua %d:",count); //xuat man hinh
fprintf(fp,"\n"); //xuong dong khi moi chuoi duoc in ra
for(i=1; i<=n; i++)
fp=fopen("C:/KETQUA.out","wt"); //mo tap tin, ghi theo van ban hoac nhi phan,
de len cai cu neu co
fprintf(fp," \n"); //de trong 1 dong de khi count xong thi dien vao
while(OK){
Result(); //xuat chuoi nhi phan thuan nghich
Next_Bit_String(); //chuoi nhi phan tiep theo
}
rewind(fp); //quay lai mo file ban dau
fprintf(fp,"%d",count); //ghi count vao dong trong da de danh phia tren
fclose(fp);
}
Trang 12for (i=1;i<=n;i++)//in cac phan tu A[i] tuong ung voi tong s
if (B[i]!=0) //neu B[i]=1 thi in A[i]
Data.in
Ketqua.Out 3
Trang 13for(i=1; i<=N; i++){
s = s + A[i]*C[i]; // Tong day con cua At=t+C[i]; // Dem so cac so 1 trong mang C}
if(s==B && t==K) // s==B : tong day con trong A bang voi B
{ // t==K : So cac so 1 trong C bang voi K
Trang 14void Day_con_tang()
{
int s=0;
for(i=1; i<=N; i++){
s = s +B[i]; //tính tổng các phần tử của chuỗi con}
if(s==K) // nếu đủ 3 phần tử
{
int j=1;
for(i=1; i<=N; i++)
if(B[i]) C[j++]=A[i]; //đưa các phần tử đó vào mảng C[j]
if (Day_tang(C,K)){ count++;
for (int i=1; i<=K;i++) fprintf(fp2,"%5d",C[i]);
fprintf(fp2,"\n");
}}}
Ketqua.Out 7
Trang 15CÁC THUẬT TOÁN XỬ LÝ KÝ TỰ Thống kê và tập hợp số lần xuất hiện của từ
//Khai báo struct của ký tự
typedef struct {
char word[20];
int solan;
} w;
// Tim tu trong mang tu[]
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 0;
}
// Tach tu trong file va tap hop lai trong mang tu
int Tim_Tap_Tu( w tu[] ){
strcpy(temp.word, s); //copy tu vua doc duoc vao temp
temp.solan=1; //ghi nhan so lan la 1
void In_Tu(w *tu, int wn){
printf("\n Ket qua: %d",wn);
fp1= fopen("c:/Ketqua.Out","w");
fprintf( fp1, "\n%d",wn);
for(int i=1; i<=wn;i++) {
printf("\n %10s %3d", tu[i].word, tu[i].solan);
fprintf(fp1, "\n %10s %3d", tu[i].word, tu[i].solan);
}
Trang 16}
int main() { wn=0; wn= Tim_Tap_Tu(tu); In_Tu(tu,wn); getch(); }
Số lần ký tự xuất hiện trong file 1 mà không xuất hiện trong file 2
Ý tưởng: Tìm số lần của từ xuất hiện trong file 1, file 2 và đưa vào mảng tu1, tu2 Sau đó,
duyệt từng từ trong mảng tu1, nếu không xuất hiện trong file tu2 thì in ra
void In_ket_qua(w *tu, int wn1)
Trang 17CÁC THUẬT TOÁN DUYỆT ĐỒ THỊ
void matranke_qua_dske (char *tenfile1,char *tenfile2 ) {
FILE *f, *g;
int n=0;int i,j, so;
if ((f=fopen(tenfile1,"r"))==NULL) return;
if ((g=fopen(tenfile2,"w"))==NULL) return;
fscanf(f,"%d ", &n); //doc n
fprintf (g, "%d",n) ; fprintf (g,"\n"); //ghi so n vao va xuong dong
for (i=1; i<= n; i++)
void matranke_qua_dscanh (char *tenfile1,char *tenfile2 ) {
FILE *f, *g; int n=0;int i,j, so;
Trang 18}
fclose(f);
rewind (g);
fprintf (g,"%4d %4d", n,socung);fclose(g); }
//CHUYỂN TỪ DANH SÁCH KỀ SANG MA TRẬN KỀ
char S[81]; char dinhke[5]; j=0; int a,num;
for ( i=0; i <=strlen(S); i++) //duyet tu 0 den het chieu dai day S
if (S[i]==' ' || S[i] =='\t' || S[i]=='\n' || S[i]=='\0') //neu ky tu thu i la trang,tab,xuongdong
{ if (j!=0) // neu j#0 ; i la hang, j la cot
{ dinhke[j]='\0'; j=0; num=atoi(dinhke); //doi tu string sang integer
Trang 19//Doi tu dscanh sang G
for (i=1; i<= m; i++)
{
fscanf(fp1,"%d %d",&u,&v); //doc va dua du lieu tu dscanh vao bien u va v
G[u][v]=G[v][u]=1; //gan gia tri G tai toa do u,v=1
Trang 20void ThuaSoNgTo( long n) {
for (int i =0 ; i< 5; i++)
if (A[i] < n) printf ("%ld ", A[i]);
}
//Tao day so ngau nhien
const int n=31;const int m =30;
void Init (int *A,int n) {
for (int i=1; i<=n ; i++) A[i]=i;
}
int randInt(int a, int b) {
return a+ rand() % (b-a+1);
}
void Hoanvi (int &a, int &b) {
int t = a; a = b ; b=t;
}
void Lietke(int *A,int m) {
for (int i=1; i<=m ; i++)
Trang 21Hoanvi (A[i], A[j]) ;
}
Lietke(A, m); getch(); }
int c[max][max];//bang chi phi; c[i][j] la chi phi di tu tp i den tp j
int x[max];//mang chua lo trinh toi uu tam thoi
int xopt[max];//mang chua lo trinh toi uu thuc su: x1->x2-> ->xn->x1
int cost=vocung;//chi phi toi uu
int sum=0;//chua tong chi phi di tu x[1] den x[i]
int tham[max];
//Ham duyet
void Duyet(int t)
{
for (int j=1;j<=n;j++)
if (tham[j]==0&&c[x[t-1]][j]!=0) //neu j chua tham va ke voi tp x[i-1]
{ x[t]=j; //chon tp tiep theo la j
tham[j]=1;
sum=sum+c[x[t-1]][j];//tinh tong chi phi di tu i den j
printf("%d %d %d ",j,t,sum);
if (t==n)
{ if (c[x[n]][x[1]]!=0) //neu tp cuoi ke voi tp xuat phat
if (sum+c[x[n]][x[1]]<cost)
{ for (int k=1;k<=n;k++) xopt[k]=x[k]; getch();
cost=sum+c[x[n]][x[1]]; //tong chi phi tim duoc cuoi cung
}
}
else if (sum<cost) Duyet(t+1);
tham[j]=0; sum=sum-c[x[t-1]][j];
}
}
void Lo_trinh_toi_uu()
{ for(int i=1;i<=n;i++) tham[i]=0;
x[1]=dxp;
tham[dxp]=1;
Duyet(2);
}
void GhiFile()
{
fp=fopen("c:/lotrinh.out","w");//mo file lotrinh de ghi
fprintf(fp,"%4d\n",cost);//ghi chi phi nho nhat
for(int i=1;i<=n;i++)//ghi x[1]->x[2]-> x[n]->
fprintf(fp,"%4d ->",xopt[i]);
fprintf(fp,"%4d",xopt[1]);//ghi x[1]
Trang 22fclose(fp);
}
//Ban dau cac cong viec deu chua duoc chon
void Init (int n)
if (B[j]) //neu cong viec B[j] chua chon
{ X[i]=j; //Mang chua thu tu cong viec
P = P +C[i][j]; //tinh tong chi phi thuc hien den cong viec do
B[j]=0; //da chon viec do roi
if (i==n) // da sap xep du n cong viec
{if ( P < FOPT)
{ FOPT = P; //Cap nhat gia tri toi uu
for(int k=1; k<=n; k++) // Cap nhat PATU
Trang 23//Ban dau cac cong viec deu chua duoc chon
void Init (int n)
if (B[j]) //neu cong viec B[j] chua chon
{ X[i]=j; //Mang chua thu tu cong viec
P = P +C[i][j]; //tinh tong chi phi thuc hien den cong viec do
B[j]=0; //da chon viec do roi
if (i==n) // da sap xep du n cong viec
{if ( P == s)
{ count++; //Cap nhat gia tri toi uu
for(int k=1; k<=n; k++) // Cap nhat PATU