Bài toán dãy con trọng lượng lớn nhất năm 2024

Dãy số ai, ai+1, …, aj với 1 ≤ i ≤ j ≤ n được gọi là dãy con của dãy số đã cho và khi đó, j-i+1 được gọi là độ dài, còn ai+ai+1…+aj được gọi là trọng lượng của dãy con này.

Yêu cầu: cho số nguyên p, trong số các dãy con của dãy số đã cho có trọng lượng không nhỏ hơn p hãy tìm dãy con có độ dài lớn nhất.

  1. Dãy con đơn điệu dài nhất 1. Mô hình Cho dãy a1,a2,..an. Hãy tìm một dãy con tăng có nhiều phần tử nhất của dãy. Đặc trưng: i) Các phần tử trong dãy kết quả chỉ xuất hiện 1 lần. Vì vậy phương pháp làm là ta sẽ dùng vòng For duyệt qua các phần tử aitrong dãy, khác với các bài toán của mô hình 4(đặc trưng là bài toán đổi tiền), các phần tử trong dãy có thể được chọn nhiều lần nên ta thực hiện bằng phương pháp cho giá trị cần quy đổi tăng dần từng đơn vị. ii) Thứ tự của các phần tử được chọn phải được giữ nguyên so với dãy ban đầu. Đặc trưng này có thể mất đi trong một số bài toán khác tùy vào yêu cầu cụ thể. Chẳng hạn bài Tam giác bao nhau. 2. Công thức QHĐ Hàm mục tiêu : f = độ dài dãy con. Vì độ dài dãy con chỉ phụ thuộc vào 1 yếu tố là dãy ban đầu nên bảng phương án là bảng một chiều. Gọi L(i) là độ dài dãy con tăng dài nhất, các phần tử lấy trong miền từ a1 đến ai và phần tử cuối cùng là ai. Nhận xét với cách làm này ta đã chia 1 bài toán lớn (dãy con của n số) thành các bài toán con cùng kiểu có kích thước nhỏ hơn (dãy con của dãy i số). Vấn đề là công thức truy hồi để phối hợp kết quả của các bài toán con. Ta có công thức QHĐ để tính L(i) như sau: • L(1) = 1. (Hiển nhiên) • L(i) = max(1, L(j)+1 với mọi phần tử j: 0

Trong bài viết này chúng ta sẽ cùng làm bài toán là tìm dãy con có tổng trọng số lớn nhất trong mảng.

Cụ thể bài toán có thể phát biểu như sau: Viết chương trình tìm dãy con có tổng trọng số lớn nhất trong mảng, tính tổng trọng số và in ra dãy con đó. Sử dụng 3 phương pháp là duyệt qua tất cả phần tử mảng, quy hoạch động và chia để trị.

Ví dụ: -5 0 -4 1 5 -2 5

Dãy con có tổng trọng số lớn nhất là: 5 -2 5 1 và có tổng trọng số là 9.

Giải bằng phương pháp duyệt qua tất cả phần tử

Đối với bài toán này thì phương pháp này là đơn giản nhất mà hầu hết ai cũng có thể nghĩ ra và làm được, tuy nhiên thuật toán lại không hề tối ưu và chạy rất tốn time nếu mảng từ vài trăm ngìn phần tử.

Ý tưởng là ta sẽ duyệt 3 vòng lặp để lấy hết từng dãy con của mảng và tính tính tổng. Duyệt đến dãy con nào có tổng trọng số lớn hơn thì ta sẽ gắn bằng maxx và lưu dãy con vào một mảng temp, thực hiện lặp cho đến khi hết tất cả dãy con lúc đó maxx chính là tổng trọng số lớn nhất, temp là dãy con đó.

  • Khóa học lập trình C/C++ từ A-Z cho người mới – Giảm giá 40% hôm nay
  • Khóa học Java cơ bản dành cho người mới bắt đầu- Giảm 40% hôm nay
  • Khóa học lập trình Android từ cơ bản đến thành thạo – Giảm ngay 40%

Ta viết chương trình như sau:

include

using namespace std; int main() { int a[]={-5,0,-4,1,5,-2,5}; //mảng a int n = sizeof(a)/4; //Số phần tử mảng a int maxsum = 0; //tổng dãy con lớn nhất int sum = 0; //sum để tính tổng từng dãy con int vtd = 0, vtc = n-1; //Lưu vị trí đầu và cuối để lát nữa lấy ra dãy con đó(hiểu là mảng temp) //Vòng lặp i j để lấy từng dãy con có trong mảng có thể sảy ra //Ví dụ dãy con có thể là từ vt1 tới vt5, vt3 tới vt4, vt2 tới vt4....v.v for (int i = 0; i < n; i++) {

for(int j=i;j
} //Hết vòng lặp ta in ra kết quả cout<

Giải bằng phương pháp quy hoạch động

Đọc thêm: Tìm hiểu thuật toán Quy hoạch động

Code quy hoạch động cho bài toán này thì nhìn rất ngắn gọn. Công thức truy hồi được tìm ra bằng cách.

Ta duyệt từ đầu mảng đi, cứ tới vị trị nào mà có tổng trọng số nhỏ hơn 0 ta bỏ luôn dãy con từ vị trí đó và tính lại sum từ phần tử tiếp theo tại vị trí đó trở đi. Bởi vì nếu đoạn trước đó đã < 0 thì cộng vào trọng số cho đoạn sau sẽ chỉ nhỏ đi chứ không thể tăng lên nên ta cắt luôn từ vị trí đó.

Ta viết code như sau:

include

using namespace std; int vt; //Hàm quy hoạch động int QHD(int a[], int n) { int temp=0, maxsum=0; //Biến temp hiểu là biến sum(tổng tạm thời), maxsum là tổng trọng số dãy con lớn nhất tìm được for(int i=0;i đoạn đó có tổng nhỏ hơn 0 nên ta gắn lại temp = 0 để bắt đầu tính tổng từ vị trí tiếp theo //Ngược lại ta cộng dồn temp+=a[i]

temp+a[i]<0?temp=0:temp+=a[i];
//Nếu temp mà lớn hớn maxsum trước đó tìm được
if(temp > maxsum){
  maxsum = temp;vt=i; //Gắn lại maxsum và vị trí kết thúc của dãy con
}
} return maxsum; } int main () {
 int a[]={-5,0,-4,1,5,-2,5};
int n = sizeof(a)/4;
 int sum = QHD(a,n); //Gọi  uy hoạch động với dãy a
//In ra tổng trọng số
 cout<
/Vì ta chỉ lưu vị trí dãy con kết thúc nên ta sẽ duyệt mảng a từ vị trí đó ngược lại qua đầu mảng và in ra từng phần tử, trừ dần đi phần tử đến khi nào sum = 0 thì tức là tổng trọng số ta tính từ đoạn đó trở đi /
 while(sum>0)
 {
   cout<
} return 0; }

Giải bằng phương pháp chia để trị

Đọc thêm: Tìm hiểu thuật toán chia để trị trong lập trình, ví dụ áp dụng

Trong bài toán này thì có lẽ sử dụng phương pháp chia để trị là phương pháp khó làm nhất. Ta sẽ chia dần mảng con nhỏ dần cho tới lúc không thể chia nhỏ, sau đó tính toán và hợp nhất lại để tính kết quả cuối cùng của bài toán.