मैंने पाया कि एक पुनरावर्ती समारोह का उपयोग कर बड़ा के लिए अच्छा नहीं था लंबाई और पूर्णांक क्योंकि यह बहुत अधिक रैम को चबाता है, और जनरेटर/पुन: प्रयोज्य-फ़ंक्शन (जो 'उपज' मानों का उपयोग करके) बहुत धीमा था और इसे क्रॉस-प्लेटफ़ॉर्म बनाने के लिए एक बड़ी लाइब्रेरी की आवश्यकता होती थी।
तो यहाँ एक गैर पुनरावर्ती सी में समाधान ++ कि अनुसार क्रमबद्ध क्रम (जो भी क्रमपरिवर्तन के लिए आदर्श है) में विभाजन पैदा करता है। मुझे यह लगता है कि यह 4 या उससे अधिक की विभाजन लंबाई के लिए प्रतीत होता है, लेकिन चालाक और संक्षिप्त पुनरावर्ती समाधानों की तुलना में यह 10 गुना तेजी से पाया गया है, लेकिन 1-3 की लंबाई के लिए प्रदर्शन आवश्यक नहीं है (और मुझे कम परवाह नहीं है लंबाई क्योंकि वे या तो दृष्टिकोण के साथ तेजी से हैं)।
// Inputs
unsigned short myInt = 10;
unsigned short len = 3;
// Partition variables.
vector<unsigned short> partition(len);
unsigned short last = len - 1;
unsigned short penult = last - 1;
short cur = penult; // Can dip into negative value when len is 1 or 2. Can be changed to unsigned if len is always >=3.
unsigned short sum = 0;
// Prefill partition with 0.
fill(partition.begin(), partition.end(), 0);
do {
// Calculate remainder.
partition[last] = max(0, myInt - sum); // Would only need "myInt - sum" if partition vector contains signed ints.
/*
*
* DO SOMETHING WITH "partition" HERE.
*
*/
if (partition[cur + 1] <= partition[cur] + 1) {
do {
cur--;
} while (
cur > 0 &&
accumulate(partition.cbegin(), partition.cbegin() + cur, 0) + (len - cur) * (partition[cur] + 1) > myInt
);
// Escape if seeked behind too far.
// I think this if-statement is only useful when len is 1 or 2, can probably be removed if len is always >=3.
if (cur < 0) {
break;
}
// Increment the new cur position.
sum++;
partition[cur]++;
// The value in each position must be at least as large as the
// value in the previous position.
for (unsigned short i = cur + 1; i < last; ++i) {
sum = sum - partition[i] + partition[i - 1];
partition[i] = partition[i - 1];
}
// Reset cur for next time.
cur = penult;
}
else {
sum++;
partition[penult]++;
}
} while (myInt - sum >= partition[penult]);
मैं कहां से "विभाजन" के साथ कुछ करना यहाँ लिखा है। वह जगह है जहां आप वास्तव में मूल्य का उपभोग करेंगे। (पिछले यात्रा पर कोड पाश के शेष निष्पादित करने के लिए जारी रहेगा, लेकिन मैं इस पाया लगातार बाहर निकलने की स्थिति के लिए जाँच की तुलना में बेहतर होने के लिए - यह बड़ा आपरेशन के अनुरूप होता है)
0,0,10
0,1,9
0,2,8
0,3,7
0,4,6
0,5,5
1,1,8
1,2,7
1,3,6
1,4,5
2,2,6
2,3,5
2,4,4
3,3,4
ओह मैं ' मैंने "हस्ताक्षरित छोटा" इस्तेमाल किया है क्योंकि मुझे अपनी लंबाई पता है और पूर्णांक कुछ सीमाओं से अधिक नहीं होगा, यह बदलें कि यदि यह आपके लिए उपयुक्त नहीं है :) टिप्पणियां जांचें; एक परिवर्तनीय (cur) को 1 या 2 की लंबाई को संभालने के लिए हस्ताक्षर किया जाना था और इसके साथ एक संबंधित if-statement है, और मैंने यह भी टिप्पणी में नोट किया है कि यदि आपके विभाजन वेक्टर ने इनट्स पर हस्ताक्षर किए हैं तो एक और पंक्ति है इसे सरल बनाया जा सकता है।
प्राप्त करने के लिए सभी रचनाएं, C++ मैं इस सरल क्रमचय रणनीति जो शुक्र डुप्लीकेट का उत्पादन नहीं करता प्रयोग करेंगे:
do {
// Your code goes here.
} while (next_permutation(partition.begin(), partition.end()));
नेस्ट कि में "विभाजन" यहाँ स्थान के साथ कुछ करते हैं, और आप जाने के लिए अच्छे हैं।
रचनाओं को खोजने का एक विकल्प (जावा कोड पर आधारित https://www.nayuki.io/page/next-lexicographical-permutation-algorithm) निम्नानुसार है। मैंने इसे next_permutation() से बेहतर प्रदर्शन करने के लिए पाया है।
// Process lexicographic permutations of partition (compositions).
composition = partition;
do {
// Your code goes here.
// Find longest non-increasing suffix
i = last;
while (i > 0 && composition[i - 1] >= composition[i]) {
--i;
}
// Now i is the head index of the suffix
// Are we at the last permutation already?
if (i <= 0) {
break;
}
// Let array[i - 1] be the pivot
// Find rightmost element that exceeds the pivot
j = last;
while (composition[j] <= composition[i - 1])
--j;
// Now the value array[j] will become the new pivot
// Assertion: j >= i
// Swap the pivot with j
temp = composition[i - 1];
composition[i - 1] = composition[j];
composition[j] = temp;
// Reverse the suffix
j = last;
while (i < j) {
temp = composition[i];
composition[i] = composition[j];
composition[j] = temp;
++i;
--j;
}
} while (true);
आप कुछ अघोषित चर वहाँ पर ध्यान देंगे, बस उन्हें कोड में पहले की घोषणा अपने सभी do-छोरों से पहले: i
, j
, pos
, और temp
(अहस्ताक्षरित शॉर्ट्स), और composition
(एक ही प्रकार और लंबाई partition
के रूप में)। विभाजन कोड स्निपेट में फॉर-लूप में इसका उपयोग करने के लिए आप i
की घोषणा का पुन: उपयोग कर सकते हैं। यह भी ध्यान दें कि last
जैसे चर का उपयोग किया जा रहा है, जो मानते हैं कि यह कोड पहले दिए गए विभाजन कोड में घोंसला है।
फिर "आपका कोड यहां जाता है" वह जगह है जहां आप अपने उद्देश्यों के लिए संरचना का उपभोग करते हैं।
संदर्भ के लिए यहां मेरे शीर्षलेख हैं।
#include <vector> // for std::vector
#include <numeric> // for std::accumulate
#include <algorithm> // for std::next_permutation and std::max
using namespace std;
यह अभी भी आप अपने CPU :) पर गुस्सा कर देगा किसी भी खासी पूर्णांकों और विभाजन लंबाई के लिए, इन तरीकों का उपयोग कर बड़े पैमाने पर गति में वृद्धि के बावजूद
चाहिए नहीं के क्रमपरिवर्तन (2, 1, 1) उस सूची में हो? –
मुझे पता था कि मैं कुछ भूल गया था। धन्यवाद, जोड़ा गया। – deleted77
पूर्णांक विभाजन की अनुमतियों को "रचनाएं" कहा जाता है। –