কম্পিউটার টিউটোরিয়াল

C++ দিয়ে অ্যারেতে সবচেয়ে বড় বিভাজ্য সাবসেট (Largest Divisible Subset) বের করা

এই টিউটোরিয়ালে একটি সমস্যা আলোচনা করা হয়েছে যেখানে পূর্ণসংখ্যার একটি অ্যারে দেওয়া আছে। আমাদের সবচেয়ে বড় সাবসেট বের করতে হবে যাতে সাবসেটের প্রতিটি জোড়ার (pair) জন্য বড় সংখ্যাটি ছোট সংখ্যাটি দিয়ে বিভাজ্য হয়। উদাহরণ −

ইনপুট: nums[] = { 1, 4, 2, 6, 7 } আউটপুট: 1 2 4 ব্যাখ্যা: সব বিভাজ্য সাবসেট: (1, 2, 4), (1, 2, 6), (1, 7) ইত্যাদি। দৈর্ঘ্য ৩-এর ২টি সাবসেট আছে।
ইনপুট: nums[] = { 1, 2, 3, 6 } আউটপুট: 6 2 1
সমাধানের পদ্ধতি

এই টিউটোরিয়ালে দুটি ভিন্ন পদ্ধতি ব্যাখ্যা করা হয়েছে।

সহজ পদ্ধতি

সহজ পদ্ধতিতে রিকার্সন (recursion) প্রয়োগ করা যায়। প্রতিটি উপাদানের জন্য দুটি অপশন: সাবসেটে রাখবো বা রাখবো না। প্রথম উপাদান নিলে, দ্বিতীয় উপাদান রাখতে হলে সেটি প্রথম উপাদান দিয়ে বিভাজ্য বা ভাগ করতে হবে। এইভাবে পুরো অ্যারে ট্রাভার্স করলে 2^n পাথ (path) বने, টাইম কমপ্লেক্সিটি O(2^n)। এখন একটি সম্ভাব্য পদ্ধতি দেখি।

দক্ষ পদ্ধতি

এই সমস্যাতেই ডাইনামিক প্রোগ্রামিং (Dynamic Programming) প্রয়োগ করে দক্ষ সমাধান করা যায়।

  • অ্যারেটি সর্ট (sort) করি যাতে বামের এলিমেন্ট ডানের 엘িমেন্ট দিয়ে বিভাজ্য হয় কিনা একবার চেক করলেই হয়।

  • Longest Increasing Subsequence (LIS)-এর মতো dp[] অ্যারে ব্যবহার করি যেটি i-তম ইনডেক্স পর্যন্ত সবচেয়ে বড় বিভাজ্য সাবসেট রাখে। প্রতিটি ইনডেক্স ১ দিয়ে ইনিশিয়ালাইজ (প্রতিটি উপাদান নিজে নিজে দিয়ে বিভাজ্য)।

  • ২য় ইনডেক্স থেকে ট্রাভার্স করে প্রতিটি উপাদানের জন্য সর্বোচ্চ বিভাজ্য সাবসেট বের করি যেটি বর্তমান ইনডেক্সে শেষ হয়।

  • অ্যারে ট্রাভার্স করে প্রতিটি উপাদানের জন্য এমন ভাজক (divisor) খুঁজি যেকোনো সর্বোচ্চ বিভাজ্য কাউন্ট থাকে। এবং বর্তমান ইনডেক্সের ভ্যালু সেটি + ১ করি।

উদাহরণ

উপরোক্ত পদ্ধতির C++ কোড

#include<bits/stdc++.h> using namespace std; int main(){     int nums[] = {1, 2, 3, 6};     int n = sizeof(nums)/sizeof(int);     // অ্যারে সর্ট করে এক শর্ত বাদ দেওয়া     sort(nums, nums+n);     vector <int> prev_res(n, -1); // ভাজক রাখার ভেক্টর     vector <int> dp(n, 1); // dp অ্যারে, ১ দিয়ে ইনিশিয়ালাইজ     int max = 1;     for (int i=1; i<n; i++){ // i-তম উপাদানের ভাজক j-তম ইনডেক্সে আছে কিনা         for (int j=0; j<i; j++){             if (nums[i] % nums[j] == 0){ // ভাজক পেলে                 if (dp[i] < dp[j] + 1){ // সাবসিকোয়েন্স বাড়লে                     dp[i] = dp[j] + 1;                     prev_res[i] = j;                 }         }         }         if(max < dp[i]) max = dp[i]; // সর্বোচ্চ সাবসেট সাইজ     }     cout << "Largest divisible subset in the array: ";     // সর্বোচ্চ সাবসেট প্রিন্ট     int k = max;     while (k >= 0){         cout << nums[k] << " ";         k = prev_res[k];     }     return 0; }
আউটপুট
Largest divisible subset in the array: 6 2 1
উপসংহার

এই টিউটোরিয়ালে আমরা একটি সমস্যা আলোচনা করেছি: দিয়ে হয়ে অ্যারেতে সবচেয়ে বড় বিভাজ্য সাবসেট বের করা যেখানে প্রতিটি জোড়ায় বড় সংখ্যা ছোট সংখ্যা দিয়ে বিভাজ্য। রিকার্সন থেকে এক্সপোনেনশিয়াল টাইম কমপ্লেক্সিটি পাওয়া যায়, তাই ডাইনামিক প্রোগ্রামিং সমাধান দেওয়া হয়েছে। এই সমস্যার C++ প্রোগ্রামও দেওয়া আছে যা C, Java, Python ইত্যাদি ভাষায়ও করা যাবে। আশা করি আপনি এই টিউটোরিয়ালটি সহায়ক পাবেন।

  1. সি শার্প প্রোগ্রাম: অ্যরেতে সবচেয়ে বড় উপাদান খুঁজে বের করা

  2. C#-এ অ্যারে থেকে শেষ মিলিত উপাদানের ইনডেক্স পাওয়া

  3. পাইথন প্রোগ্রাম অ্যারেতে সবচেয়ে বড় এলিমেন্ট বের করা

  4. পাইথনে অ্যারে থেকে সর্বোচ্চ এলিমেন্ট বের করা