Professional Documents
Culture Documents
ThamLapPhong 20215449 Baocaothuchanh
ThamLapPhong 20215449 Baocaothuchanh
BUỔI SỐ 04 – TUẦN 39
Hà Nội, 2023
Mục lục
Bài thực hành số 4 – Tuần 39 ................................................................................................................... 3
Bài tập 4.1. . Đảo ngược một danh sách liên kết đơn Hãy hoàn thiện các hàm thao tác trên một danh
sách liên kết: Thêm một phần tử vào đầu danh sách liên kết In danh sách Đảo ngược danh sách liên kết
(yêu cầu độ phức tạp thời gian O(N) và chi phí bộ nhớ dùng thêm O(1)) .............................................. 3
Bài tập 4.2. Một điểm trong không gian 2 chiều được biểu diễn bằng pair. Hãy viết hàm tính diện tích
tam giác theo tọa độ 3 đỉnh. ................................................................................................................. 7
Bài tập 4.3. Một vector trong không gian 3 chiều được biểu diễn bằng tuple<double, double, double>.
Hãy viết hàm tính tích có hướng của 2 vector. ...................................................................................... 8
Bài tập 4.4. Cho hai std::vector, hãy xóa hết các phần tử chẵn, sắp xếp giảm dần các số trong cả 2
vector và trộn lại thành một vector cũng được sắp xếp giảm dần. ......................................................... 9
Bài tập 4.5. Viết hàm void dfs(vector< list<int> > adj) thực hiện thuật toán DFS không sử dụng đệ quy
trên đồ thị biểu diễn bằng danh sách kề. Đồ thị có n đỉnh được đánh số từ 1 đến n. Thuật toán DFS xuất
phát từ đỉnh 1. Các đỉnh được thăm theo thứ tự ưu tiên từ trái sang phải trong danh sách kề. Yêu cầu
hàm trả ra thứ tự các đỉnh được thăm (những đỉnh không thể thăm từ đỉnh 1 thì không phải in ra).. .... 13
Bài tập 4.6. Viết hàm void bfs(vector< list<int> > adj) thực hiện thuật toán BFS không sử dụng đệ quy
trên đồ thị biểu diễn bằng danh sách kề. Đồ thị có n đỉnh được đánh số từ 1 đến n. Thuật toán BFS xuất
phát từ đỉnh 1. Các đỉnh được thăm theo thứ tự ưu tiên từ trái sang phải trong danh sách kề. Yêu cầu
hàm trả ra thứ tự các đỉnh được thăm (những đỉnh không thể thăm từ đỉnh 1 thì không phải in ra). ..... 16
Bài tập 4.7. Viết các hàm thực hiện các phép giao và hợp của hai tập hợp được biểu diễn bằng set. ... 17
Bài tập 4.8 Viết các hàm thực hiện các phép giao và hợp của hai tập hợp mờ được biểu diễn bằng map.
Trong đó mỗi phần tử được gán cho một số thực trong đoạn [0..1] biểu thị độ thuộc của phần tử trong
tập hợp, với độ thuộc bằng 1 nghĩa là phần tử chắc chắn thuộc vào tập hợp và ngược lại độ thuộc bằng
0 nghĩa là phần tử chắc chắn không thuộc trong tập hợp. Phép giao và hợp của 2 tập hợp được thực
hiện trên các cặp phần tử bằng nhau của 2 tập hợp, với độ thuộc mới được tính bằng phép toán min và
max của hai độ thuộc.. ....................................................................................................................... 20
Bài tập 4.9. Cài đặt thuật toán Dijkstra trên đồ thị vô hướng được biểu diễn bằng danh sách kề sử dụng
std::priority_queue Cụ thể, bạn cần cài đặt hàm vector<int> dijkstra(const vector< vector< pair<int,
int> > >&adj) nhận đầu vào là danh sách kề chứa các cặp pair<int, int> biểu diễn đỉnh kề và trọng số
tương ứng của cạnh. Đồ thị gồm n đỉnh được đánh số từ 0 tới n-1. Hàm cần trả `vector<int>` chứa n
phần tử lần lượt là khoảng cách đường đi ngắn nhất từ đỉnh 0 tới các đỉnh 0, 1, 2, ..., n-1. .................. 23
Bài tập 4.10. Search Engine Xây dựng một máy tìm kiếm (search engine) đơn giản. Cho N văn bản và
Q truy vấn. Với mỗi truy vấn, cần trả về văn bản khớp với truy vấn đó nhất.. ..................................... 26
Bài tập 4.11.Bảo vệ lâu đài. Bức tường bao quanh một lâu đài nọ được cấu thành từ n đoạn tường
được đánh số từ 1 đến n . Quân giặc lên kế hoạch tấn công lâu đài bằng cách gửi ai tên giặc đánh vào
đoạn tường thứ i . Để bảo vệ lâu đài có tất cả s lính. Do các đoạn tường có chất lượng khác nhau nên
khả năng bảo vệ tại các đoạn tường cũng khác nhau. Cụ thể tại đoạn tường thứ i , mỗi lính có thể đẩy
#include <iostream>
using namespace std;
// Tham Lap Phong 20215449
struct Node {
int data;
Node* next;
Node(int data) {
this->data = data;
next = NULL;
}
};
prev = current;
current = next;
return head;
}
int main() {
int n, u;
cin >> n;
Node* head = NULL;
for (int i = 0; i < n; ++i){
cin >> u;
head = prepend(head, u);
}
head = reverse(head);
return 0;
}
return 0;
}
Bài tập 4.2. Một điểm trong không gian 2 chiều được biểu diễn bằng pair. Hãy viết hàm
tính diện tích tam giác theo tọa độ 3 đỉnh.
SOURCE CODE:
#include <iostream>
#include <cmath>
#include <iomanip>
#include <utility>
using namespace std;
using Point = pair<double, double>;
double ab = distance(a,b);
double ac = distance(a,c);
double bc = distance(b,c) ;
double p = (ab+bc+ac)/2;
return sqrt(p * (p-ab) * (p-bc) * (p-ac));
}
}
int main() {
cout << setprecision(2) << fixed;
cout << area({1, 2}, {2.5, 10}, {15, -5.25}) << endl;
return 0;
}
Bài tập 4.3. Một vector trong không gian 3 chiều được biểu diễn bằng tuple<double,
double, double>. Hãy viết hàm tính tích có hướng của 2 vector.
SOURCE CODE:
c1 = get<2>(a)*get<0>(b) - get<2>(b)*get<0>(a),
c2 = get<0>(a)*get<1>(b) - get<0>(b)*get<1>(a);
return Vector{c0,c1,c2};
Bài tập 4.4. Cho hai std::vector, hãy xóa hết các phần tử chẵn, sắp xếp giảm dần các số
trong cả 2 vector và trộn lại thành một vector cũng được sắp xếp giảm dần.
SOURCE CODE:
#include <iostream>
#include <vector>
#include <algorithm>
vector<int> tmp;
for(int v : a){
if(v % 2 != 0) tmp.push_back(v);
return tmp;
vector<int> sum;
for(int v : a){
sum.push_back(v);
for(int v : b){
sum.push_back(v);
return sum;
int main() {
int m, n, u;
std::vector<int> a, b;
a.push_back(u);
b.push_back(u);
a = delete_even(a);
print_vector(a);
b = delete_even(b);
print_vector(b);
sort_decrease(a);
print_vector(a);
sort_decrease(b);
print_vector(b);
print_vector(c);
return 0;
Bài tập 4.5. Viết hàm void dfs(vector< list<int> > adj) thực hiện thuật toán DFS không
sử dụng đệ quy trên đồ thị biểu diễn bằng danh sách kề. Đồ thị có n đỉnh được đánh số từ
1 đến n. Thuật toán DFS xuất phát từ đỉnh 1. Các đỉnh được thăm theo thứ tự ưu tiên từ
trái sang phải trong danh sách kề. Yêu cầu hàm trả ra thứ tự các đỉnh được thăm (những
đỉnh không thể thăm từ đỉnh 1 thì không phải in ra)..
SOURCE CODE:
void dfs(vector< list<int> > adj) {
stack<int> S;
vector<bool> visited(adj.size());
while (!S.empty()) {
int u=S.top();
if (!visited[u]){
visited[u] = true;
if(!visited[v]){
S.push(v);
}else { S.pop();}
queue<int> Q;
vector<bool> visited(adj.size());
while (!Q.empty()) {
int u=Q.front();
if (!visited[u]){
visited[u] = true;
if (!adj[u].empty()){
if(!visited[v]){
Q.push(v);
}else { Q.pop();}
Bài tập 4.7. Viết các hàm thực hiện các phép giao và hợp của hai tập hợp được biểu diễn
bằng set.
Source code:
// Tham Lap Phong 20215449
set<T> c;
for(T v:a){
c.insert(v);
for (T v: b){
c.insert (v);
return c;
template<class T>
set <T> c;
for (T v : a){
for (T u : b){
if (v==u) index++;
if (index != 0)
c.insert(v);
return c;
Bài tập 4.8 Viết các hàm thực hiện các phép giao và hợp của hai tập hợp mờ được biểu
diễn bằng map. Trong đó mỗi phần tử được gán cho một số thực trong đoạn [0..1] biểu
thị độ thuộc của phần tử trong tập hợp, với độ thuộc bằng 1 nghĩa là phần tử chắc chắn
thuộc vào tập hợp và ngược lại độ thuộc bằng 0 nghĩa là phần tử chắc chắn không thuộc
trong tập hợp. Phép giao và hợp của 2 tập hợp được thực hiện trên các cặp phần tử bằng
nhau của 2 tập hợp, với độ thuộc mới được tính bằng phép toán min và max của hai độ
thuộc..
SOURCE CODE:
// Tham Lap Phong 20215449
template<class T>
map<T, double> fuzzy_set_union(const map<T, double> &a, const map<T, double> &b) {
if (v.first == u.first){
break;
ans.insert({v.first, second});
if (v.first == u.first){
break;
ans.insert({v.first, second});
return ans;
template<class T>
map<T, double> fuzzy_set_intersection(const map<T, double> &a, const map<T, double> &b) {
if (v.first == u.first){
break;
return ans;
Bài tập 4.9. Cài đặt thuật toán Dijkstra trên đồ thị vô hướng được biểu diễn bằng danh
sách kề sử dụng std::priority_queue Cụ thể, bạn cần cài đặt hàm vector<int>
dijkstra(const vector< vector< pair<int, int> > >&adj) nhận đầu vào là danh sách kề chứa
các cặp pair<int, int> biểu diễn đỉnh kề và trọng số tương ứng của cạnh. Đồ thị gồm n
đỉnh được đánh số từ 0 tới n-1. Hàm cần trả `vector<int>` chứa n phần tử lần lượt là
khoảng cách đường đi ngắn nhất từ đỉnh 0 tới các đỉnh 0, 1, 2, ..., n-1.
Source Code:
struct comp{
};
dist[i] = INT_MAX;
q.push({i, dist[i]});
while (!q.empty()){
q.pop();
int u = u_pair.first; // lay ra dinh co thu tu uu tien nhat trong hang doi
int v = v_pair.first;
q.push({v, dist[v]});
return dist;
Bài tập 4.10. Search Engine Xây dựng một máy tìm kiếm (search engine) đơn giản. Cho
N văn bản và Q truy vấn. Với mỗi truy vấn, cần trả về văn bản khớp với truy vấn đó
nhất..
Source code
#include<iostream>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
//priority queue ch?a các c?p (x,y) trong ?ó x là s? hi?u v?n b?n, y là ?i?m s? c?a v?n b?n ?ó
struct cmp{
//2 v?n b?n cùng ?i?m th́ v?n b?n có s? hi?u th?p h?n s? ? trên
};
int dem=0;
return dem;
map<string,int> M;
int max=0;
for(auto x:M) {
//max ch?a s? l?n xu?t hi?n nhi?u nh?t c?a t? xu?t hi?n nhi?u nh?t
if (x.second>max) max=x.second;
return max;
int dem=0;
for(auto x:a){
for(auto y:x){
if(y==t) {
dem++;
break;}
return dem;
if (f(t,d,a)==0) return 0;
double TF=0.5+0.5*f(t,d,a)/max(d,a);
double IDF=log2(N/df(t,a));
return TF*IDF;
int main(){
freopen("input.txt","r",stdin);
int N,Q;
cin>>N;
getchar();
//VB ch?a các vector là các v?n b?n, các vector ?ó ch?a các t? trong v?n b?n
vector<vector<string>> VB;
VB.resize(N);
for(int i=0;i<N;i++){
string str;
str.resize(10);
char c;
int dem=0;
L0: do{
if(c=='\n') goto L1;//c là xu?ng ḍ ng th́ nha? L1:cho xâu ?ang dang d? thành 1 t? vào v?n b?n hi?n
th?i,b? ??m v? 0,reset str
else if(c==',') goto L2;//c là d?u ph?y th́ l?u xâu ?ó thành m?t t?, dem v? 0,reset str và quay L0 b?t
??u t? ti?p theo
else{
str[dem]=c;
dem++;}
}while(1);
L2:{
VB[i].push_back(str);
dem=0;
str.clear();
str.resize(10);
goto L0;};
L1:{
VB[i].push_back(str);
dem=0;
str.clear();
str.resize(10);
};
cin>>Q;
getchar();
vector<vector<string>> TV;
TV.resize(Q);
for(int i=0;i<Q;i++){
string str;
str.resize(10);
int dem=0;
L3: do{
c=getchar();
else{
str[dem]=c;
dem++;}
}while(1);
L5:{
TV[i].push_back(str);
dem=0;
str.clear();
str.resize(10);
goto L3;};
L4:{
TV[i].push_back(str);
dem=0;
str.clear();
str.resize(10);
};
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
for(auto x:TV){
for(int i=0;i<N;i++){
double score=0;
for(auto y:x){
score=score+tscore(y,i,VB,N);
//Ta ??y ?i?m c?a v?n b?n i v?i truy v?n x và hàng ??i
pq.push(make_pair(i,score));
//L?y ra ??nh c?a hàng ??i chính là ?i?m cao nh?t v?i truy v?n x, ta c?ng 1 do truy v?n ?ánh s? t? 1
cout<<pq.top().first+1<<endl;
while(!pq.empty()) {pq.pop();}
*VÌ case test dài nên em xin phép chỉ để ảnh output
CASE 1:
CASE 2:
CASE 3:
CASE 4
CASE 5:
Bài tập 4.11.Bảo vệ lâu đài. Bức tường bao quanh một lâu đài nọ được cấu thành từ n
đoạn tường được đánh số từ 1 đến n . Quân giặc lên kế hoạch tấn công lâu đài bằng cách
gửi ai tên giặc đánh vào đoạn tường thứ i . Để bảo vệ lâu đài có tất cả s lính. Do các
đoạn tường có chất lượng khác nhau nên khả năng bảo vệ tại các đoạn tường cũng khác
nhau. Cụ thể tại đoạn tường thứ i , mỗi lính có thể đẩy lùi tấn công của ki tên giặc. Giả
sử đoạn tường thứ i có xi lính. Khi đó nếu số tên giặc không vượt quá xi×ki thì không
có tên giặc nào lọt vào được qua đoạn tường này. Ngược lại sẽ có ai−xi×ki tên giặc lọt
vào lâu đài qua đoạn tường này. Yêu cầu hãy viết chương trình phân bố lính đứng ở các
đoạn tường sao cho tổng số lính là s và tổng số lượng tên giặc lọt vào lâu đài là nhỏ nhất.
.
SOURCE CODE:
#include<bits/stdc++.h>
using namespace std;
struct data {
int ai;
int ki;
};
struct compare{
bool operator() (data a, data b){
int ra, rb;
};
int n, s, kill_enemy, total_enemy;
priority_queue<data, vector<data>, compare> p_q;
void input(){
cin >> n >> s;
kill_enemy = 0;
total_enemy = 0;
for(int i=0; i<n; i++){
int tmp1, tmp2;
cin >> tmp1 >> tmp2;
total_enemy += tmp1;
p_q.push(data(tmp1, tmp2));
}
}
void solve(){
} else {
int nenemy = inf.ai - inf.ki;
p_q.push(data(nenemy, inf.ki));
kill_enemy += inf.ki;
s -= 1;
}
}
int calc_enemy(){
return total_enemy - kill_enemy;
}
int main(){
input();
solve();
cout << calc_enemy();
return 0;
}
CASE 1:
case 2:
CASE 3:
CASE 4:
CASE 5:
Bài tập 4.12. Lược đồ Cho một lược đồ gồm n cột chữ nhật liên tiếp nhau có chiều rộng
bằng 1 và chiều cao lần lượt là các số nguyên không âm h1,h2,…,hn . Hãy xác định hình
chữ nhật có diện tích lớn nhất có thể tạo thành từ các cột liên tiếp.
Source code:
#include<bits/stdc++.h>
long long n;
vector<long long> L; // mang trai luu tru gia tri ben trai gan nhat nho hon gia tri dang xet
vector<long long> R; // mang phai luu tru gia tri ben phai gan nhat nho hon gia tri dang
xet
void inputData(){
vt.push_back(tmp);
void solve(){
while(true){
inputData();
if(n==0) return;
// Xu ly o day
stack<long long> st; // 1 stack de thuc hien thuat toan ghi ra cac gia tri L, R
L.resize(n+2);
R.resize(n+2);
L[st.top()] = i;
st.pop();
st.push(i);
R[st.top()] = i;
st.pop();
st.push(i);
// Xoa mang truoc khi bat dau vong lap moi ( mang vt, mang L, mang R)
vt.erase(vt.begin(),vt.end());
L.erase(L.begin(),L.end());
int main(){
solve();
return 0;
TEST CASE:
CASE 1:
CASE 3:
CASE 4:
Bài tập 4.13. Đếm xâu con Cho một xâu nhị phân độ dài n . Hãy viết chương trình đếm
số lượng xâu con chứa số ký tự 0 và số ký tự 1 bằng nhau.
Source code:
#include<bits/stdc++.h>
string str;
int n, cnt;
cnt = 0;
n = str.length();
if(i==0){
if(str[i] == '0'){
slg0[i] = 1;
slg1[i] = 0;
} else {
slg0[i] = 0;
slg1[i] = 1;
continue;
if(str[i] == '0'){
slg0[i] = slg0[i-1] + 1;
slg1[i] = slg1[i-1];
} else {
slg0[i] = slg0[i-1];
slg1[i] = slg1[i-1] + 1;
void solve(){
if(i==0){
} else {
int main(){
ios_base::sync_with_stdio(false); cin.tie(NULL);
input();
solve();
TEST CASE:
CASE 1
Case 3:
CASE 4:
CASE 5: