সি ++ (হিউরিস্টিক): 2, 4, 10, 16, 31, 47, 75, 111, 164, 232, 328, 445, 606, 814, 1086
এই পিটার টেইলরের ফলাফলের পিছনে সামান্য হয় 1 থেকে 3 জন্য নিম্ন হচ্ছে n=7
, 9
এবং 10
। সুবিধাটি হ'ল এটি অনেক দ্রুত, তাই আমি এটির উচ্চতর মানের জন্য চালাতে পারি n
। এবং এটি কোনও অভিনব গণিত ছাড়াই বোঝা যায়। ;)
বর্তমান কোডটি চালিয়ে যাওয়ার জন্য মাত্রাযুক্ত n=15
। প্রতিটি বারের বৃদ্ধির জন্য রান টাইম মোটামুটি 4 এর গুণক দ্বারা বৃদ্ধি পায় n
। উদাহরণস্বরূপ, এটি 0.008 সেকেন্ডের জন্য n=7
, 0.07 সেকেন্ডের জন্য n=9
, 1.34 সেকেন্ডের জন্য n=11
, 27 সেকেন্ডের জন্য n=13
এবং 9 মিনিটের জন্য ছিল n=15
।
আমি ব্যবহৃত দুটি মূল পর্যবেক্ষণ আছে:
- মানগুলিতে নিজেরাই অপারেটিংয়ের পরিবর্তে, হিউরিস্টিক অ্যারে গণনা করে। এটি করার জন্য, প্রথমে সমস্ত অনন্য গণনা অ্যারের তালিকা তৈরি করা হয়।
- ছোট মান সহ অ্যারে গণনা আরও বেশি সুবিধাজনক, যেহেতু তারা সমাধানের জায়গাগুলির কম অপসারণ করে। এই প্রতিটি গণনা উপর ভিত্তি করে তৈরি
c
পরিসীমা ব্যতীত c / 2
করার 2 * c
অন্যান্য মান থেকে। এর ছোট মানগুলির জন্য c
, এই ব্যাপ্তিটি আরও ছোট, যার অর্থ এটি ব্যবহার করে খুব কম মান বাদ পড়ে।
স্বতন্ত্র গণনা অ্যারে তৈরি করুন
আমি এইটির উপর দৃ force় শক্তি প্রয়োগ করেছি, সমস্ত মানগুলির মধ্যে পুনরাবৃত্তি করেছি, তাদের প্রত্যেকের জন্য গণনা অ্যারের উত্পন্ন করছি এবং ফলাফলটি পৃথক করে দেব। এটি অবশ্যই আরও দক্ষতার সাথে করা যেতে পারে তবে আমরা যে ধরণের মান নিয়ে কাজ করছি তার পক্ষে এটি যথেষ্ট ভাল।
এটি ছোট মানগুলির জন্য অত্যন্ত দ্রুত। বৃহত্তর মানগুলির জন্য, ওভারহেড যথেষ্ট পরিমাণে হয়ে যায়। উদাহরণস্বরূপ, এর জন্য n=15
এটি পুরো রানটাইমের প্রায় 75% ব্যবহার করে। এর চেয়ে অনেক বেশি যাওয়ার চেষ্টা করার সময় অবশ্যই এটি দেখার ক্ষেত্র হবে n=15
। এমনকি সমস্ত মানগুলির জন্য গণনা অ্যারেগুলির তালিকা তৈরির জন্য কেবল মেমরির ব্যবহার সমস্যাযুক্ত হতে শুরু করবে।
অনন্য গণনা অ্যারেগুলির জন্য মানগুলির সংখ্যার প্রায় 6% n=15
। এই আপেক্ষিক গণনা বড় হওয়ার সাথে সাথে আরও ছোট হয় n
।
অ্যারে মান গণনা করার লোভী নির্বাচন
অ্যালগরিদমের মূল অংশটি একটি সাধারণ লোভী পদ্ধতির সাহায্যে উত্পন্ন তালিকা থেকে অ্যারে মান গণনা নির্বাচন করে।
তত্ত্বের উপর ভিত্তি করে যে ছোট সংখ্যা গণনা করে অ্যারে ব্যবহার করা উপকারী, গণনা অ্যারেগুলি তাদের গণনাগুলির যোগফল অনুসারে বাছাই করা হয়।
তারপরে সেগুলি যথাযথভাবে চেক করা হয় এবং পূর্ববর্তী ব্যবহৃত মানগুলির সাথে সামঞ্জস্যপূর্ণ হলে একটি মান নির্বাচন করা হয়। সুতরাং এটিতে অনন্য গণনা অ্যারেগুলির মধ্যে একটি একক রৈখিক পাস জড়িত থাকে, যেখানে প্রতিটি প্রার্থীকে পূর্বে নির্বাচিত মানগুলির সাথে তুলনা করা হয়।
হিউরিস্টিক কীভাবে সম্ভাব্য উন্নতি করতে পারে সে সম্পর্কে আমার কিছু ধারণা রয়েছে। তবে এটি একটি যুক্তিসঙ্গত সূচনা পয়েন্টের মতো মনে হয়েছিল এবং ফলাফলগুলি বেশ ভাল দেখাচ্ছে looked
কোড
এটি অত্যন্ত অনুকূল নয়। আমার এক পর্যায়ে আরও বিস্তৃত ডেটা কাঠামো ছিল, তবে এটিকে বাইরে সাধারণ করার জন্য আরও কাজ করা দরকার ছিল n=8
, এবং পারফরম্যান্সের পার্থক্য খুব একটা সুস্পষ্ট মনে হয়নি।
#include <cstdint>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <sstream>
#include <iostream>
typedef uint32_t Value;
class Counter {
public:
static void setN(int n);
Counter();
Counter(Value val);
bool operator==(const Counter& rhs) const;
bool operator<(const Counter& rhs) const;
bool collides(const Counter& other) const;
private:
static const int FIELD_BITS = 4;
static const uint64_t FIELD_MASK = 0x0f;
static int m_n;
static Value m_valMask;
uint64_t fieldSum() const;
uint64_t m_fields;
};
void Counter::setN(int n) {
m_n = n;
m_valMask = (static_cast<Value>(1) << n) - 1;
}
Counter::Counter()
: m_fields(0) {
}
Counter::Counter(Value val) {
m_fields = 0;
for (int k = 0; k < m_n; ++k) {
m_fields <<= FIELD_BITS;
m_fields |= __builtin_popcount(val & m_valMask);
val >>= 1;
}
}
bool Counter::operator==(const Counter& rhs) const {
return m_fields == rhs.m_fields;
}
bool Counter::operator<(const Counter& rhs) const {
uint64_t lhsSum = fieldSum();
uint64_t rhsSum = rhs.fieldSum();
if (lhsSum < rhsSum) {
return true;
}
if (lhsSum > rhsSum) {
return false;
}
return m_fields < rhs.m_fields;
}
bool Counter::collides(const Counter& other) const {
uint64_t fields1 = m_fields;
uint64_t fields2 = other.m_fields;
for (int k = 0; k < m_n; ++k) {
uint64_t c1 = fields1 & FIELD_MASK;
uint64_t c2 = fields2 & FIELD_MASK;
if (c1 > 2 * c2 || c2 > 2 * c1) {
return false;
}
fields1 >>= FIELD_BITS;
fields2 >>= FIELD_BITS;
}
return true;
}
int Counter::m_n = 0;
Value Counter::m_valMask = 0;
uint64_t Counter::fieldSum() const {
uint64_t fields = m_fields;
uint64_t sum = 0;
for (int k = 0; k < m_n; ++k) {
sum += fields & FIELD_MASK;
fields >>= FIELD_BITS;
}
return sum;
}
typedef std::vector<Counter> Counters;
int main(int argc, char* argv[]) {
int n = 0;
std::istringstream strm(argv[1]);
strm >> n;
Counter::setN(n);
int nBit = 2 * n - 1;
Value maxVal = static_cast<Value>(1) << nBit;
Counters allCounters;
for (Value val = 0; val < maxVal; ++val) {
Counter counter(val);
allCounters.push_back(counter);
}
std::sort(allCounters.begin(), allCounters.end());
Counters::iterator uniqEnd =
std::unique(allCounters.begin(), allCounters.end());
allCounters.resize(std::distance(allCounters.begin(), uniqEnd));
Counters solCounters;
int nSol = 0;
for (Value idx = 0; idx < allCounters.size(); ++idx) {
const Counter& counter = allCounters[idx];
bool valid = true;
for (int iSol = 0; iSol < nSol; ++iSol) {
if (solCounters[iSol].collides(counter)) {
valid = false;
break;
}
}
if (valid) {
solCounters.push_back(counter);
++nSol;
}
}
std::cout << "result: " << nSol << std::endl;
return 0;
}
L1[i]/2 <= L2[i] <= 2*L1[i]
।