Professional Documents
Culture Documents
2022.2 BC - IT3040 20215467 TruongDinhVanQuyen Buoi4 727636
2022.2 BC - IT3040 20215467 TruongDinhVanQuyen Buoi4 727636
Contents
Bài thực hành số 3 – Tuần 39......................................................................................................................3
Bài tập 1: Đảo ngược một danh sách liên kết đơn...................................................................................3
Bài tập 2: Tính diện tích tam giác.............................................................................................................7
Bài tập 3: Tính tích có hướng của 2 vector..............................................................................................8
Bài tập 4: Thao tác với vector................................................................................................................10
Bài tập 5:................................................................................................................................................15
Bài tập 6:................................................................................................................................................18
Bài tập 7:................................................................................................................................................21
Bài tập 8:................................................................................................................................................24
Bài tập 9:................................................................................................................................................28
Bài tập 10: Search Engine......................................................................................................................32
Bài tập 12. Lược đồ................................................................................................................................57
Bài tập 13: Đếm xâu con........................................................................................................................61
Hãy hoàn thiện các hàm thao tác trên một danh sách liên kết:
#include <iostream>
struct Node {
int data;
Node* next;
Node(int data) {
next = NULL;
};
newNode->next = head;
return newNode;
while(head){
cout<<head->data<<" ";
head = head->next;
cout<<endl;
while(head){
next = head->next;
head->next = prev;
prev=head;
head = next;
return prev;
int main() {
int n, u;
cin >> n;
cin >> u;
print(head);
head = reverse(head);
print(head);
return 0;
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 double
area(Point a, Point b, Point c) tính diện tích tam giác theo tọa đ ộ 3 đ ỉnh. Trong đó,
Point là kiểu được định nghĩa sẵn trong trình chấm như sau: using Point =
pair<double, double>;
#include <cmath>
#include <iomanip>
#include <utility>
double p = (ab+cb+ac)/2;
return sqrt(p*(p-ab)*(p-cb)*(p-ac));
int main() {
cout << area({1, 2}, {2.5, 10}, {15, -5.25}) << endl;
return 0;
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 Vector cross_product(Vector a, Vector b) tính tích có
hướng của 2 vector. Trong đó Vector là kiểu dữ liệu được định nghĩa sẵn trong
trình chấm như sau: using Vector = tuple<double, double, double>;
#include <iostream>
#include <cmath>
#include <iomanip>
get<2>(a)*get<0>(b)-get<0>(a)*get<2>(b),
get<0>(a)*get<1>(b)-get<1>(a)*get<0>(b));
int main() {
cout << get<0>(c) << ' ' << get<1>(c) << ' ' << get<2>(c) << endl;
return 0;
Cho hai 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.
#include <iostream>
#include <vector>
#include <algorithm>
a.erase(remove_if(a.begin(),a.end(), [] (int x) {
return x%2==0;
}),a.end());
sort(a.rbegin(),a.rend());
vector<int> c;
merge(a.begin(),a.end(),b.begin(),b.end(), back_inserter(c),greater<int>());
return c;
int main() {
int m, n, u;
std::vector<int> a, b;
a.push_back(u);
b.push_back(u);
delete_even(a);
print_vector(a);
delete_even(b);
print_vector(b);
print_vector(a);
sort_decrease(b);
print_vector(b);
print_vector(c);
return 0;
Bài tập 5:
Viết hàm 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ề vector< list<int> > . Đồ 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).
#include<iostream>
#include<vector>
#include<list>
#include<stack>
stack<int> S;
vector<bool> visited(adj.size());
while(!S.empty()){
int u = S.top();
if(!visited[u]){
visited[u]=true;
cout<<u<<endl;
if(!adj[u].empty()){
int v = adj[u].front();
adj[u].pop_front();
if(!visited[v]){
S.push(v);
else S.pop();
int main() {
int n = 7;
adj.resize(n + 1);
adj[1].push_back(2);
adj[2].push_back(4);
adj[1].push_back(3);
adj[3].push_back(4);
adj[3].push_back(5);
adj[5].push_back(2);
adj[2].push_back(7);
adj[6].push_back(7);
dfs(adj);
Bài tập 6:
Viết hàm 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ề vector< list<int> > . Đồ 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).
#include<iostream>
#include<vector>
#include<list>
#include<queue>
queue<int> Q;
vector<bool> visited(adj.size());
while(!Q.empty()){
int u = Q.front();
if(!visited[u]){
visited[u] = true;
cout<<u<<endl;
for(int v : adj[u]){
if(!visited[v]){
Q.push(v);
Q.pop();
int main() {
int n = 7;
adj.resize(n + 1);
adj[2].push_back(4);
adj[1].push_back(3);
adj[3].push_back(4);
adj[3].push_back(5);
adj[5].push_back(2);
adj[2].push_back(7);
adj[6].push_back(7);
bfs(adj);
Bài tập 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
#include <iostream>
#include <set>
template<class T>
set<T> c =a;
c.insert(b.begin(),b.end());
return c;
template<class T>
set<T> c;
if(b.find(x)!=b.end()){
c.insert(x);
return c;
template<class T>
int main() {
return 0;
Bài tập 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.
#include<iostream>
#include<map>
template<class T>
if (res.count(x.first)){
else res.insert(x);
return res;
template<class T>
if(it != b.end())
return res;
template<class T>
cout << "(" << x.first << ", " << x.second << ") ";
int main () {
map<int, double> a = {{1, 0.2}, {2, 0.5}, {3, 1}, {4, 0.6}, {5, 0.7}};
map<int, double> b = {{1, 0.5}, {2, 0.4}, {4, 0.9}, {5, 0.4}, {6, 1}};
return 0;
Bài tập 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 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.
#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<climits>
priority_queue<pair<int, int>> Q;
Q.push({0,0});
while(!Q.empty()){
int du = -Q.top().first;
int u = Q.top().second;
Q.pop();
for(auto e : adj[u]){
int v = e.first;
int c = e.second;
d[v] = d[u] + c;
Q.push({-d[v], v});
return d;
int main() {
int n = 9;
adj[v].push_back({u, w});
};
add_edge(0, 1, 4);
add_edge(0, 7, 8);
add_edge(1, 7, 11);
add_edge(1, 2, 8);
add_edge(2, 3, 7);
add_edge(2, 8, 2);
add_edge(3, 4, 9);
add_edge(3, 5, 14);
add_edge(4, 5, 10);
add_edge(5, 6, 2);
add_edge(6, 7, 1);
add_edge(6, 8, 6);
add_edge(7, 8, 7);
cout << "distance " << 0 << "->" << i << " = " << distance[i] << endl;
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.
Case 1:
Case 2:
Case 3:
Case 4:
Case 5:
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.
#include<iostream>
#include<cmath>
#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{
c=getchar();
if(c=='\n') goto L1;//c là xuống dò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);
char c;
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;};
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;
//Với mỗi từ y thuộc truy vấn x ta tính điểm với từng văn bản i và cộng dồn
lại
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();}
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×kithì
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.
Case 1:
Case 2:
Case 3:
Case 4:
Case 5:
. Quân giặc lên kế hoạch tấn công lâu đài bằng cách gửi ai
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
tên giặc.
có xi
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.*/
#include<iostream>
#include<map>
#include<queue>
struct cmp{
//x y là cặp : first là số tên địch còn lại,second là khả năng chống trả
int gth1,gth2;
//Nếu số tên địch > Khả năng chống trả thì nếu thêm 1 lính độ giảm thiệt hại
=khả năng chống trả
gth1=(x.first-x.second>=0)?x.second:x.first;
gth2=(y.first-y.second>=0)?y.second:y.first;
};
int main(){
int n, s;
cin>>n>>s;
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
int arr[2*n]={};
cin>>arr[i];
if(i%2==1) pq.push(make_pair(arr[i-1],arr[i]));
pair<int,int> temp;
while(s>0){
//Cho thêm 1 lính vào tường tương ứng với độ giảm thiệt hại cao
temp=pq.top();
pq.pop();
temp.first=temp.first-temp.second;
pq.push(temp);
s--;
int count;
while(!pq.empty()){
//Ngược lại thì không có tên địch lọt vào lâu đài
if(pq.top().first>0) count=count+pq.top().first;
pq.pop();
Case1:
Case2:
Case3:
Case4:
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.*/
#include<iostream>
#include<vector>
#include<queue>
//Ý tưởng: Mỗi hcn dc tạo thành đều có một hình chữ nhật con có h bé nhất
//Từ mỗi hcn con cao hi ta xây dựng hcn to có S lớn nhất mà hi là bé nhất b ằng
cách loang rộng ra 2 bên cho đến khi gặp hcn có hj nhỏ hơn
int main(){
freopen("input1.txt","r",stdin);
int N;
cin>>N;
int arr[N];
for(int i=0;i<N;i++){
cin>>arr[i];
int max=0;
int L=0;//So hcn lien tiep ben trai hcn hi co chieu cao>=hi
int R=0;//So hcn lien tiep ben phai hcn hi co chieu cao>=hi
int j=i-1;
//Nếu chiều cao hcn i nhân với tổng số hcn vẫn nhỏ hơn max hiện thời thì b ỏ
qua hcn này
if(arr[i]*N<=max) continue;
while(j>=0){
if(arr[j]>=arr[i]) {L++;j--;continue;}
else break;
j=i+1;
while(j<N){
if(arr[j]>=arr[i]) {R++;j++;continue;}
else break;
if((L+R+1)*arr[i]>max) max=(L+R+1)*arr[i];
cout<<max;
return 1;
Case1:
Case2:
Case3:
Case4:
Case5:
. 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.*/
#include<iostream>
#include<cstring>
#include<vector>
int main(){
freopen("input3.txt","r",stdin);
string str;
cin>>str;
vector<int> a;
int dem0=0,dem1=0,dasd0=0,dasd1=0;
if(str[i]=='0') {a.push_back(0);dem0++;}
else {a.push_back(1);dem1++;}
int N=a.size();
int dem=0;
//Xét từ phần tử i
for(int i=0;i<N;i++){
int S=0;
if(a[i]==0) {S--;dasd0++;}
else {S++;dasd1++;}
//tmp để lưu giá trị của dasd để dùng cho vòng lặp
int tmp0=dasd0,tmp1=dasd1;
for(int j=i+1;j<N;j++){
if(a[j]==0) {S--;tmp0++;}
else {S++;tmp1++;}
if(S==0) dem++;
//Nếu S<0 tức xâu hiện đang xét nhiều 0 hơn 1, nếu các ph ần t ử 1 ch ưa xét
đến(dem1-tmp) không đủ để xâu về cân bằng thì break
cout<<dem;