You are on page 1of 16

Đề cương ôn tập phân tích thiết kế thuật toán (CNTTVA1&CNTTVA2)

1. Hình thức thi viết 90 phút gồm 03 bài trong đề cương và 01 bài nâng cao
2. Yêu cầu, nêu được ý tưởng thuật toán, tính toán minh họa được kết quả
của thuật toán bằng tay, viết được code
3. Nội dung gồm các bài sau
I. Thuật toán tham lam
a. Búp bê Nga
Bạn hãy tính toán giúp Tichpx xem khi lồng hết cỡ có thể thì còn
bao nhiêu con và tổng kích thước những con to nhất chứa những
con còn lại bằng bao nhiêu để tichpx chọn ba lô cho phù hợp nhé
Input
Dòng đầu chứa số nguyên dương n là số con búp bê và một số
nguyên dương k nếu 2 con búp bê chênh nhau lớn hơn hoặc bằng k
là có thể lồng vào nhau được.
Dòng tiếp theo chứa kích thước của các con búp bê gồm n giá trị
nguyên dương a[i].
Output
Gồm hai số nguyên dương là số con búp bê ngoài cùng sau khi
lồng và tổng kích thước của những con ngoài cùng đó.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n, k, a[100005];
long long sum = 0;
cin >> n >> k;
priority_queue<int> Q;
queue<int> q;
for(int i=1; i<=n; i++)
{
cin >> a[i];
Q.push(a[i]);
}
for(int i=1; i<=n; i++)
{
q.push(Q.top());
if (q.front() < Q.top() + k)
{
sum += Q.top();
}
else q.pop();
Q.pop();
}
cout << q.size() << " " << sum;
}

b. Buôn dưa lê

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main(){
ll n,k,m,res=0,a,t=0;
cin>>n>>k>>m;
// for(int i=1;i<=n;i++) cin>>a[i];
// sort(a+1,a+n+1,greater<ll>());
queue<ll> Q;
for(int i=1;i<n+k;i++){ // den ngay n+k thi tat ca hong
het
if(i<=n) cin>>a;
else a=0;
Q.push(a);
while(Q.size()>k) Q.pop(); // qua k ngay -> hong
t=0;
while(Q.size() && t+Q.front()<=m){// thu het cac
thua
t+=Q.front();Q.pop();
}
if(Q.size()) {// neu van con thua chin thi thu cho du m
Q.front()-=m-t;
t=m;
}
res+=t;
}
cout<<res;

c. Giao hàng
Titi nhận được n món hàng cần giao, món hàng thứ i giao không
trễ quá thời gian t sẽ được thưởng vi tiền. Giả sử cứ một đơn vị
thời gian thì Titi giao được một món hàng, bạn hãy giúp Titi xếp
thứ tự giao hàng thế nào để được nhiều tiền thưởng nhất nhé
Input
Dòng đầu số nguyên dương là số món hàng Titi phải giao
Tiếp theo n dòng mỗi dòng chứa hai giá trị là ti và vi nếu món hàng
này Titi giao không trễ quá ti thì sẽ được thưởng vi trong đó ti và vi
lớn hơn 1 nhỏ hơn 10 mũ 6.
Output
Số tiền được thưởng cao nhất có thể nếu Titi chọn được cách giao
hợp lý nhất.
#include<bits/stdc++.h>
using namespace std;

int main(){
long long n;
cin>>n;
long long res=0;
vector<long long> A[1000005];
priority_queue<long long> Q;

for(int i=1;i<=n;i++){
long long x,y;
cin>>x>>y;
A[x].push_back(y);
}

for(int i=1e5;i>0;i--)
{
for(auto it:A[i]) Q.push(it);
if(Q.size()){
res+=Q.top();
Q.pop();
}
}
cout<<res;
}

d. Làm bóng tuyết


#include <bits/stdc++.h>
using namespace std;
int main(){
long long n, t [100005], v[100005], p =0, s;
priority_queue<long long, vector<long long>,
greater<long long> > Q;
cin>>n;
for(int i=1; i<=n;i++){
cin>>v[i];
}
for(int i=1;i<=n;i++){
cin>>t[i];
}
for(int i=1;i<=n;i++){

s=0;
Q.push(v[i]+p);
while (Q.size() && Q.top() -p <= t[i]){
s+= Q.top()-p;
Q.pop();
}
cout<< s+ t[i] *Q.size()<< " ";
p+= t[i];
if(Q.size()==0) p=0;
}
}

II. Thuật toán quy hoạch động


e. Bài toán đổi tiền
Ngân hàng có n mệnh giá tiền có số lượng mỗi tờ tiền là vô hạn
gồm a1, a2,..,an. Một người muốn đổi số tiền M theo các mệnh giá
tiền này hãy tìm cách đổi sao cho số tờ tiền là ít nhất
Input
Dòng đầu chứa hai số n là số loại mệnh giá ngân hàng có và số truy
vấn q.

Dòng tiếp theo chứa n số nguyên dương không vượt quá 10 mũ 4


đôi một khác nhau là các loại mệnh giá tiền mà ngân hàng có

Cuối cùng gồm q dòng mỗi dòng một giá trị Mvà số tiền muốn
đổi

Ouput
Gồm dòng mỗi dòng một số nguyên dương là số tờ tiền ít nhất đổi
được, trong trường hộp không đổi được tiền thì xuất -1
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,q,M,a[105], C[10005]={};
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i];
fill(C+1,C+10001,1e9);
for(int i=1;i<=n;i++)
for(int j=a[i];j<=10000;j++) C[j]= min(C[j],1+C[j-
a[i]]);
while(q--)
{
cin>>M;
cout<<(C[M]==1e9?-1:C[M]) <<"\n";
}
}

f. Xâu con chung dài nhất

#include<bits/stdc++.h>
using namespace std;

struct xcc{
int n,m,C[100][100]={};
string x,y;
void sol(){
cin>>x; n= x.size(); x="$"+x;
cin>>y; m= y.size(); y="$"+y;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
C[i][j]=x[i]==y[j]?1+C[i-1][j-1]:max(C[i-1][j],C[i][j-1]);
}
if(C[n][m]) {cout<<"do dai xccdn: "<<C[n][m]<<"XAU LA: ";
trace(n,m);}
else cout<<"khong co xau con chung";
}
void trace(int n,int m){
if(C[n][m]==0) return;
while(C[n][m]==C[n-1][m]) n--;
while(C[n][m]==C[n][m-1]) m--;
trace(n-1,m-1); cout<<x[n];
}
};
int main(){
xcc X; X.sol();
}

g. Sắp xếp ba lô
Cho đồ vật, mỗi đồ vật có kích thước và giá trị lần lượt là <w1,
v1>, <w2,v2>,..,<wn,vn> một ba lô có kích thước M , hãy tìm cách
xếp các đồ vật vào ba lô sao cho tổng kích thước các đồ vật không
vượt quá kích thước của ba lô, mà tổng giá trị thu được là lớn nhất.
Input
Dòng đầu chứa số đồ vật
Tiếp theo dòng mỗi dòng chứa hai giá trị tương ứng là kích thước
và giá trị các đồ vật
Tiếp theo chứa số lần truy vấn
Tiếp theo là dòng mỗi dòng tương ứng với một kích thước ba lô
cần truy vấn
Output
Gồm dòng mỗi dòng tương ứng với tổng giá trị lớn nhất theo từng
truy vấn
#include<bits/stdc++.h>
using namespace std;
int main()
{

int n,a[106],b[106],C[10006]={}, M,q;


cin>>n;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
for(int i=1;i<=n;i++)
for(int j=1e4;j>=a[i];j--)
C[j]=max(C[j],b[i]+C[j-a[i]]);
cin>>q;
while(q--)
{
cin>>M; cout<<C[M]<<"\n";
}
}

h. Bảng số
Tichpx có 1 bảng số dạng ma trận số aij(n*m) Nhiệm vụ của bạn là
đi từ góc trên trái xuống góc dưới phải mỗi bước chỉ dịch một ô
trang phải hoặc xuống dưới sao cho tổng các giá trị thu được là lớn
nhất. Bạn hãy chỉ ra giá trị lớn nhất thu được.

Input
Dòng thứ nhất gồm 2 số n và m là cỡ của ma trận

n dòng tiếp theo mỗi dòng mỗi dòng chứa m số nguyên có trị tuyệt
đối nhỏ hơn 1000

Output
Một số nguyên là giá trị lớn nhất thu được
#include<bits/stdc++.h>
using namespace std;

struct number{
int n,m,C[1005][1005]={},a[1005][1005];
void sol(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) cin>>a[i][j];
C[1][1]=a[1][1];
for(int j=2;j<=m;j++) C[1][j]=C[1][j-1]+a[1][j];
for(int i=2;i<=n;i++) C[i][1]=C[i-1][1]+a[i][1];
for(int i=2;i<=n;i++)
for(int j=2;j<=m;j++) C[i][j]=max(C[i-1][j],C[i][j-1])
+a[i][j];
cout<<C[n][m];
}
};

int main(){
number n; n.sol();
}

III. Quay lui


i. Đổi tiền

j. Dãy con liên tục có tổng lớn nhất


Cho một dãy số nguyên a1,a2 … an, một dãy con liên tục được
sinh ra bằng cách lấy các phần tử liền nhau nào đó trong dãy.
Nhiệm vụ của bạn tìm tổng lớn nhất của tất cả các dãy con liên tục
sinh ra bởi dãy số nguyên ban đầu.

Input
Dòng đầu là số nguyên dương N (1<=N<=10^5)
Dòng 2 là N số nguyên có giá trị (-1000<=ai<=1000) mỗi số cách
nhau bằng ít nhất 1 khoảng trống
Output
Một số nguyên là tổng lớn nhất.
#include<bits/stdc++.h>
using namespace std;
long long MAX(int *a,int L, int R){
if(L==R) return a[L];
int M= (L+R)/2;
long long A= MAX(a,L,M);
long long B= MAX(a,M+1,R);
long long CL,CR,u,v;
CL=u=a[M] ;
for(int i=M-1;i>=L;i--) {u+=a[i]; if(CL<u) CL=u;}
CR=v=a[M+1];
for(int i=M+2;i<=R;i++) {v+=a[i]; if(CR<v) CR=v;}
return max({A,B,CL+CR}); // neu co 2 thi k can {}, nhieu
thi can{}
}
int main()
{
int n;
cin>>n;
int a[n+5];
for(int i=1;i<=n;i++) cin>>a[i];
cout<<MAX(a,1,n);
}

k. Người đi du lịch

IV. Chia để trị

l. xâu Fibonacci
m. Cắt thanh kim loại
n. Đếm số nghịch thế (cây IT)

You might also like