एक अतिभारित हवाई जहाज से फाटेस्ट लोगों को फेंकना।


200

मान लीजिए कि आपको हवाई जहाज मिल गया है, और यह ईंधन पर कम है। जब तक विमान 3000 पाउंड यात्री भार नहीं गिराता, तब तक वह अगले हवाई अड्डे तक नहीं पहुंच पाएगा। अधिकतम जीवन बचाने के लिए, हम सबसे भारी लोगों को पहले विमान से फेंकना चाहेंगे।

और हाँ, हवाई जहाज पर लाखों लोग हैं, और हम पूरी सूची को क्रमबद्ध किए बिना सबसे भारी यात्रियों को खोजने के लिए एक इष्टतम एल्गोरिदम चाहते हैं।

यह C ++ में कोड करने की कोशिश कर रहे कुछ के लिए एक प्रॉक्सी समस्या है। मैं वजन से यात्री के प्रकट होने पर एक "आंशिक_शर्त" करना चाहता हूं, लेकिन मुझे नहीं पता कि मुझे कितने तत्वों की आवश्यकता है। मैं अपना खुद का "आंशिक_सॉर्ट" एल्गोरिथ्म ("आंशिक_सॉर्ट_एसीम्युलेट_ंटिल") लागू कर सकता था, लेकिन मैं सोच रहा हूं कि क्या मानक एसटीएल का उपयोग करने का कोई आसान तरीका है।


5
यदि मानव की सादृश्यता आप उन लोगों को फेंकने से शुरू कर सकते हैं जो अधिक वजन का होता है तो X, उदाहरण के लिए 120 किग्रा, क्योंकि उन लोगों के बीच सबसे अधिक संभावना होती है।
रेडएक्स

132
क्या सभी यात्री एल्गोरिथम के किसी भी चरण में सहयोग करेंगे?
लायर कोगन

34
इस तरह के विषय क्यों मुझे आईटी से प्यार है।
मार्कस

14
क्या मैं पूछ सकता हूं कि यह किस एयरलाइन के लिए है? मैं यह सुनिश्चित करना चाहता हूं कि मैं केवल छुट्टियों के मौसम से पहले ही उनके साथ उड़ूं - अपने आप को खत्म करने के बाद नहीं।
jp2code

24
उचित उपकरणों के साथ यात्री सहयोग की आवश्यकता नहीं है (जैसे निर्मित तराजू के साथ इजेक्टर सीटें)।
जिम फ्रेड

जवाबों:


102

एक तरीका एक मिन हीप ( std::priority_queueC ++ में) का उपयोग करना होगा । यहां बताया गया है कि आप ऐसा कैसे करेंगे, यह मानकर कि आपके पास एक MinHeapवर्ग है। (हां, मेरा उदाहरण C # में है। मुझे लगता है कि आपको इसका विचार मिल गया है।)

int targetTotal = 3000;
int totalWeight = 0;
// this creates an empty heap!
var myHeap = new MinHeap<Passenger>(/* need comparer here to order by weight */);
foreach (var pass in passengers)
{
    if (totalWeight < targetTotal)
    {
        // unconditionally add this passenger
        myHeap.Add(pass);
        totalWeight += pass.Weight;
    }
    else if (pass.Weight > myHeap.Peek().Weight)
    {
        // If this passenger is heavier than the lightest
        // passenger already on the heap,
        // then remove the lightest passenger and add this one
        var oldPass = myHeap.RemoveFirst();
        totalWeight -= oldPass.Weight;
        myHeap.Add(pass);
        totalWeight += pass.Weight;
    }
}

// At this point, the heaviest people are on the heap,
// but there might be too many of them.
// Remove the lighter people until we have the minimum necessary
while ((totalWeight - myHeap.Peek().Weight) > targetTotal)
{
    var oldPass = myHeap.RemoveFirst();
    totalWeight -= oldPass.Weight; 
}
// The heap now contains the passengers who will be thrown overboard.

मानक संदर्भों के अनुसार, चलने का समय आनुपातिक होना चाहिए n log k, जहां nयात्रियों की संख्या है और kढेर पर अधिकतम आइटम हैं। यदि हम मानते हैं कि यात्रियों का वजन आमतौर पर 100 पाउंड या अधिक होगा, तो यह संभावना नहीं है कि ढेर में किसी भी समय 30 से अधिक आइटम होंगे।

सबसे खराब स्थिति यह होगी कि यात्रियों को सबसे कम वजन से लेकर उच्चतम तक के क्रम में प्रस्तुत किया जाता है। इसके लिए आवश्यक है कि प्रत्येक यात्री को ढेर में जोड़ा जाए, और प्रत्येक यात्री को ढेर से हटाया जाए। फिर भी, एक लाख यात्रियों के साथ और यह मानते हुए कि सबसे हल्के का वजन 100 पाउंड है, n log kएक छोटी संख्या में काम करता है।

यदि आपको यात्रियों का वजन अनियमित रूप से मिलता है, तो प्रदर्शन बहुत बेहतर है। मैं एक सिफारिश इंजन के लिए कुछ इस तरह का उपयोग करता हूं (मैं कई मिलियन की सूची से शीर्ष 200 आइटम का चयन करता हूं)। मैं आमतौर पर केवल 50,000 या 70,000 वस्तुओं के साथ समाप्त होता हूं, जो वास्तव में ढेर में जोड़े जाते हैं।

मुझे संदेह है कि आपको कुछ समान दिखाई देगा: आपके अधिकांश उम्मीदवार खारिज कर दिए जाएंगे क्योंकि वे पहले से ही सबसे हल्के व्यक्ति की तुलना में हल्के हैं। और Peekएक O(1)ऑपरेशन है।

हीप सिलेक्ट और क्विक सलेक्ट के प्रदर्शन के बारे में अधिक जानकारी के लिए, देखें जब थ्योरी अभ्यास से मिलती है । लघु संस्करण: यदि आप कुल मदों की संख्या का 1% से कम का चयन कर रहे हैं, तो हीप चयन त्वरित चयन पर एक स्पष्ट विजेता है। 1% से अधिक, फिर क्विक सलेक्ट का उपयोग करें या एक संस्करण जैसे कि Introselect


1
सोपबॉक्स ने तेज उत्तर पोस्ट किया।
मूविंग डक

7
मेरे पढ़ने के लिए, सोपबॉक्स का जवाब जिम मेंथेल के जवाब के नैतिक समकक्ष है। SoapBox ने C ++ में अपना कोड लिखा था, और इस प्रकार वह एक std :: set का उपयोग करता है, जिसमें एक ही लॉग (N) मिनहाप के रूप में समय जोड़ता है।
IvyMike

1
एक रैखिक समय समाधान है। मैं इसे जोड़ दूँगा।
नील जी

2
वहाँ एक न्यूनतम-ढेर के लिए एक एसटीएल वर्ग है:std::priority_queue
bdonlan

3
@MingDuck: शायद आपने गलत समझा। मेरा कोड एक खाली हीप बनाता है, जैसे कि SoapBox का कोड एक खाली सेट बनाता है। मुख्य अंतर, जैसा कि मैं इसे देखता हूं, यह है कि उसका कोड अतिरिक्त वजन के सेट को अधिक वजन के रूप में ट्रिम कर देता है, जबकि मेरा अतिरिक्त को बनाए रखता है और अंत में इसे ट्रिम करता है। भारी लोगों को खोजने वाली सूची से गुजरने पर उनका सेट आकार में संभावित रूप से कम हो जाएगा। वजन की सीमा तक पहुंचने के बाद मेरा ढेर समान आकार का रहता है, और मैं सूची में अंतिम आइटम की जांच करने के बाद इसे ट्रिम करता हूं।
जिम मिसल

119

यह आपकी प्रॉक्सी समस्या के लिए मदद नहीं करेगा, हालाँकि:

1,000,000 यात्रियों के लिए 3000 पाउंड वजन गिराने के लिए, प्रत्येक यात्री को हारना होगा (3000/1000000) = 0.003 प्रति व्यक्ति। कि हर एक शर्ट, या जूते, या शायद हर किसी को बचाने के लिए नाखूनों की कतरन के माध्यम से हासिल किया जा सकता है। इससे वजन कम होने से पहले कुशल संग्रह और जेटसन की जरूरत बढ़ जाती है क्योंकि विमान अधिक ईंधन का उपयोग करता है।

असल में, वे अब बोर्ड पर नाखूनों की क्लिपिंग की अनुमति नहीं देते हैं, इसलिए यह बाहर है।


14
समस्या को देखने और वास्तव में बेहतर तरीका खोजने की क्षमता से प्यार करें।
fncomp

19
आप एक प्रतिभाशाली हैं। :)
जोनाथन

3
मुझे लगता है कि जूते अकेले इस कवर करेगा
बतख राँभना

0.003 पाउंड 0.048 औंस है, जो कि एक औंस के 1/20 से कम है। तो अगर विमान में साठ लोगों में से एक मात्र तीन-औंस शैम्पू नियम का लाभ उठा रहा था, तो आप उस सभी शैम्पू को फेंककर दिन बचा सकते थे।
रेयान लुंडी

43

नीचे सीधे समाधान के बजाय एक सरल कार्यान्वयन है। मुझे नहीं लगता कि कोई तेज़ तरीका है जो 100% सही है।

size_t total = 0;
std::set<passenger> dead;
for ( auto p : passengers ) {
    if (dead.empty()) {
       dead.insert(p);
       total += p.weight;
       continue;
    }
    if (total < threshold || p.weight > dead.begin()->weight)
    {
        dead.insert(p);
        total += p.weight;
        while (total > threshold)
        {
            if (total - dead.begin()->weight < threshold)
                break;
            total -= dead.begin()->weight;
            dead.erase(dead.begin());
        }
    }
 }

यह "मृत लोगों" के सेट को भरने तक काम करता है जब तक कि यह दहलीज से नहीं मिलता है। एक बार दहलीज पूरी हो जाने के बाद, हम उन यात्रियों की सूची से गुजरते हैं जो किसी भी ऐसे व्यक्ति को खोजने की कोशिश कर रहे हैं जो सबसे हल्के मृत व्यक्ति से भारी हो। जब हमें एक मिल गया है, तो हम उन्हें सूची में जोड़ते हैं और फिर सूची से सबसे हल्के लोगों को "सहेजना" शुरू करते हैं जब तक कि हम किसी और को नहीं बचा सकते।

सबसे खराब स्थिति में, यह पूरी सूची के एक प्रकार के बारे में प्रदर्शन करेगा। लेकिन सबसे अच्छे मामले में ("मृत सूची" पहले एक्स लोगों के साथ ठीक से भर जाती है) यह प्रदर्शन करेगा O(n)


1
मुझे लगता है कि आपको इसके अलावा अन्य के लिए अपडेट करना totalहोगा continue;, यह वह उत्तर है जो मैं पोस्ट करने जा रहा था। सुपर फास्ट सॉल्यूशन
डक डक

2
यह सही उत्तर है, यह सबसे तेज़ उत्तर है, यह सबसे कम जटिलता वाला उत्तर भी है।
Xander ट्यूलिप

आप शायद dead.begin () को कैच करके थोड़ा अधिक निचोड़ सकते हैं और ब्रांचिंग को कम करने के लिए सामान को थोड़ा पीछे कर सकते हैं, जो आधुनिक प्रोसेसर पर काफी धीमा है
18

dead.begin () सबसे अधिक संभावना है और यह ठीक है कि लगभग निश्चित रूप से सिर्फ एक डेटा एक्सेस के लिए इनबिल्ट होगा। लेकिन हाँ, इफ़्स में से कुछ के आसपास जाने से शाखाओं को कम करके थोड़ा अधिक प्रदर्शन होगा ... लेकिन शायद पठनीयता के लिए महान लागत पर।
साबुन बॉक्स

1
यह तार्किक रूप से सुरुचिपूर्ण है, और ओपी की सभी आवश्यकताओं को संबोधित करता है, जिसमें सामने वाले यात्रियों की # जानकारी नहीं है। हालांकि, एसटीएल मैप्स और सेट्स के साथ काम करने में पिछले 5 महीनों में बहुत खर्च करने के बाद, मुझे यकीन है कि इसका इस्तेमाल करने वाले व्यापक प्रदर्शन अपंग प्रदर्शन करेंगे। बस सेट को आबाद करें, और फिर दाईं से बाईं ओर चलने तक भारी लोगों का योग 3,000 से अधिक है। यादृच्छिक क्रम में प्रस्तुत 1 मिलियन तत्वों का एक सेट, i5 पर ~ 30 मिलियन / सेकंड पर लोड होगा || i 3.4 3.4hz कोर धीमी गति से कम से कम 100X Iteration। KISS यहाँ जीतेंगे।
user2548100

32

सभी यात्रियों का मानना ​​है कि सहयोग करेगा: एक समानांतर छँटाई नेटवर्क का उपयोग करें । (यह भी देखें इस )

यहाँ एक लाइव प्रदर्शन है

अपडेट: वैकल्पिक वीडियो (1:00 पर जाएं)

तुलना-विनिमय के लिए लोगों के जोड़े पूछना - आप इससे तेज नहीं प्राप्त कर सकते।


1
यह अभी भी एक प्रकार है और O (nlogn) होगा। आप निश्चित रूप से तेजी से प्राप्त कर सकते हैं, ओ के रूप में (nlogk) जहां k << n, समाधान प्रदान किया गया है।
एडम

1
@ एडम: यह समानांतर प्रकार है। सॉर्टिंग में O (nlog n) SEQUENTIAL चरणों की निचली सीमा होती है। हालांकि वे समता कर सकते हैं, इसलिए समय जटिलता बहुत कम हो सकती है। उदाहरण के लिए देखें cs.umd.edu/~gasarch/ramsey/parasort.pdf
Lior Kogan

1
ठीक है, ओपी का कहना है "यह कुछ ऐसी चीज़ों के लिए एक प्रॉक्सी समस्या है जिसे मैं C ++ में कोड करने की कोशिश कर रहा हूं।" इसलिए यदि यात्री सहयोग करेंगे, तो भी वे आपके लिए गणना नहीं करेंगे। यह एक साफ-सुथरा विचार है, लेकिन यह कागज की धारणा है कि आपको nप्रोसेसर मिलते हैं।
एडम

@LiorKogan - लाइव डेमो वीडियो अब यूट्यूब पर उपलब्ध नहीं है
Adelin

@ एडेलिन: धन्यवाद, वैकल्पिक वीडियो जोड़ा गया
कोगन

21

@Blastfurnace सही रास्ते पर था। आप क्विकसेट का उपयोग करते हैं जहां पिवोट्स वजन थ्रेसहोल्ड हैं। प्रत्येक विभाजन लोगों के एक सेट को विभाजित करता है, और लोगों के प्रत्येक सेट के लिए कुल वजन लौटाता है। आप तब तक उचित बाल्टी तोड़ते रहें जब तक कि आपके बाल्टी उच्चतम वजन वाले लोगों के 3000 पाउंड से अधिक न हो, और आपकी सबसे कम बाल्टी जो उस सेट में है, उसमें 1 व्यक्ति है (जो कि आगे विभाजित नहीं हो सकता है।)

यह एल्गोरिथ्म रैखिक समय परिशोधन है, लेकिन द्विघात सबसे खराब स्थिति है। मुझे लगता है कि यह केवल रैखिक समय का एल्गोरिथ्म है


यहाँ एक पायथन समाधान है जो इस एल्गोरिथ्म को दिखाता है:

#!/usr/bin/env python
import math
import numpy as np
import random

OVERWEIGHT = 3000.0
in_trouble = [math.floor(x * 10) / 10
              for x in np.random.standard_gamma(16.0, 100) * 8.0]
dead = []
spared = []

dead_weight = 0.0

while in_trouble:
    m = np.median(list(set(random.sample(in_trouble, min(len(in_trouble), 5)))))
    print("Partitioning with pivot:", m)
    lighter_partition = []
    heavier_partition = []
    heavier_partition_weight = 0.0
    in_trouble_is_indivisible = True
    for p in in_trouble:
        if p < m:
            lighter_partition.append(p)
        else:
            heavier_partition.append(p)
            heavier_partition_weight += p
        if p != m:
            in_trouble_is_indivisible = False
    if heavier_partition_weight + dead_weight >= OVERWEIGHT and not in_trouble_is_indivisible:
        spared += lighter_partition
        in_trouble = heavier_partition
    else:
        dead += heavier_partition
        dead_weight += heavier_partition_weight
        in_trouble = lighter_partition

print("weight of dead people: {}; spared people: {}".format(
    dead_weight, sum(spared)))
print("Dead: ", dead)
print("Spared: ", spared)

आउटपुट:

Partitioning with pivot: 121.2
Partitioning with pivot: 158.9
Partitioning with pivot: 168.8
Partitioning with pivot: 161.5
Partitioning with pivot: 159.7
Partitioning with pivot: 158.9
weight of dead people: 3051.7; spared people: 9551.7
Dead:  [179.1, 182.5, 179.2, 171.6, 169.9, 179.9, 168.8, 172.2, 169.9, 179.6, 164.4, 164.8, 161.5, 163.1, 165.7, 160.9, 159.7, 158.9]
Spared:  [82.2, 91.9, 94.7, 116.5, 108.2, 78.9, 83.1, 114.6, 87.7, 103.0, 106.0, 102.3, 104.9, 117.0, 96.7, 109.2, 98.0, 108.4, 99.0, 96.8, 90.7, 79.4, 101.7, 119.3, 87.2, 114.7, 90.0, 84.7, 83.5, 84.7, 111.0, 118.1, 112.1, 92.5, 100.9, 114.1, 114.7, 114.1, 113.7, 99.4, 79.3, 100.1, 82.6, 108.9, 103.5, 89.5, 121.8, 156.1, 121.4, 130.3, 157.4, 138.9, 143.0, 145.1, 125.1, 138.5, 143.8, 146.8, 140.1, 136.9, 123.1, 140.2, 153.6, 138.6, 146.5, 143.6, 130.8, 155.7, 128.9, 143.8, 124.0, 134.0, 145.0, 136.0, 121.2, 133.4, 144.0, 126.3, 127.0, 148.3, 144.9, 128.1]

3
+1। यह एक दिलचस्प विचार है, हालांकि मुझे यकीन नहीं है कि यह काफी रैखिक है। जब तक मैं कुछ याद नहीं कर रहा हूं, आपको बाल्टी के कुल वजन की गणना करने के लिए वस्तुओं पर पुनरावृति करना होगा, और आपको हर बार विभाजित होने पर उच्च बाल्टी (कम से कम आंशिक रूप से) को फिर से गणना करना होगा। यह अभी भी सामान्य मामले में मेरे ढेर-आधारित दृष्टिकोण से अधिक तेज़ होगा, लेकिन मुझे लगता है कि आप जटिलता को कम कर रहे हैं।
जिम मेंथेल

2
@ जिम: इसे क्विकसेक् स के रूप में एक ही जटिलता होनी चाहिए । मुझे पता है कि विकिपीडिया पर विवरण सबसे अच्छा नहीं है, लेकिन इसका कारण यह है कि यह रैखिक परिशोधन का समय है कि हर बार जब आप विभाजन करते हैं, तो आप विभाजन के केवल एक पक्ष के साथ काम करते हैं। गैर-कठोरता से, कल्पना करें कि प्रत्येक विभाजन दो में लोगों के सेट को विभाजित करता है। फिर, पहला चरण ओ (एन), फिर ओ (एन / 2), आदि और, एन + एन / 2 + एन / 4 + ... = 2 एन लेता है।
नील जी

2
@ जिम: वैसे भी, आपके एल्गोरिथ्म में सबसे खराब स्थिति का समय होता है, जबकि मेरा सबसे अच्छा औसत समय होता है। मुझे लगता है कि वे दोनों अच्छे समाधान हैं।
नील जी

2
@JimMischel, NeilG: codepad.org/FAx6hbtc मैंने सत्यापित किया कि सभी के परिणाम समान हैं, और उन्होंने जिम को सही किया। FullSort: 1828 टिक। जिममिशेल: 312 टिक। साबुनबॉक्स 109 टिक। नीलग: 641 टिक।
मूविंग डक

2
@NeilG: codepad.org/0KmcsvwD मैंने अपने एल्गोरिथम तरीके को तेजी से लागू करने के लिए std :: विभाजन का उपयोग किया। stdsort: 1812 टिक। FullHeap 312 टिक। सोपबॉक्स / जिममिचेल: 109 टिक, नीलग: 250 टिक।
मूकिंग डक

11

यह मानते हुए कि, लोगों के वजन की तरह, आपके पास यह एक अच्छा विचार है कि ओ (एन) में उन्हें छांटने के लिए अधिकतम और न्यूनतम मूल्यों का क्या उपयोग किया जा सकता है। फिर सूची के सबसे हल्के सिरे से सबसे हल्के की ओर काम करें। कुल चलने का समय: O (n)। दुर्भाग्य से, STL में एक मूलांक प्रकार का कार्यान्वयन नहीं है, लेकिन यह लिखने के लिए बहुत सरल है।


मैं एक सामान्य मूलांक सॉर्ट का उपयोग नहीं करूंगा, क्योंकि आपको उत्तर प्राप्त करने के लिए सूची को पूरी तरह से सॉर्ट करने की आवश्यकता नहीं है।
मूइंग डक

1
स्पष्ट करने के लिए, एक मूलांक तरह है एक अच्छा विचार है। बस एक अनुकूलित अनुकूलित लिखना सुनिश्चित करें।
मूविंग डक

1
@Mooing: यह सच है कि आपको एक पूर्ण मूलांक सॉर्ट नहीं करना है, लेकिन जिस समय मैंने इसे पोस्ट किया था, उसमें कोई O (n) एल्गोरिदम पोस्ट नहीं किए गए थे और यह देखने में आसान था। मुझे लगता है कि नील जी का जवाब अब वह सबसे अच्छा है कि उन्होंने इसे पूरी तरह से समझाया और स्पष्ट रूप से अपने चयन के लिए धुरी के रूप में माध्यिका का उपयोग करना शुरू कर दिया। लेकिन एक मानक मूलांक प्रकार का उपयोग करना थोड़ा आसान है और सूक्ष्म कार्यान्वयन कीड़े होने की संभावना कम है, इसलिए मैं अपना उत्तर छोड़ने जा रहा हूं। एक स्वनिर्धारित आंशिक मूलांक की तरह करना निश्चित रूप से तेज़ होगा, लेकिन ऐसा नहीं है।
कीथ इरविन

6

आप "सॉर्ट किए गए" की तुलना में एक अलग एबॉर्ट नियम के साथ एक आंशिक क्विकर का उपयोग क्यों नहीं करते हैं। आप इसे चला सकते हैं और फिर केवल उच्च आधे का उपयोग कर सकते हैं और तब तक चल सकते हैं जब तक कि इस उच्च आधे के भीतर के वजन में कम से कम भार नहीं होता है, जिसे अब बाहर फेंक दिया जाना चाहिए, जब तक आप पुनरावृत्ति में एक कदम पीछे नहीं जाते हैं और सूची को क्रमबद्ध करते हैं। उसके बाद आप उस छांटे गए सूची के उच्च अंत से लोगों को फेंकना शुरू कर सकते हैं।


मुझे लगता है कि नील जी के एल्गोरिथ्म के पीछे यही मूल अवधारणा है
मूविंग डक

यह क्विकसेलेक्ट का सार है, जिसे नील जी उपयोग कर रहे हैं।
माइकल डोनोहे

6

बड़े पैमाने पर समानांतर टूर्नामेंट क्रमबद्ध: -

एक मानक तीन सीटों को मानते हुए:

  1. विंडो सीट में यात्रियों से पूछें कि क्या वे विंडो सीट के व्यक्ति की तुलना में भारी हैं या नहीं।

  2. बीच की सीट के यात्रियों से पूछें कि भारी होने पर सीट में यात्री के साथ स्वैप करें।

  3. बायीं गलियारे वाली सीट के यात्री से दाईं ओर वाली सीट आईडी में यात्री से स्वैप करने के लिए कहें जो कि वे भारी होते हैं।

  4. बुलबुला सही गलियारे की सीट में यात्रियों को सॉर्ट करता है। (N पंक्तियों के लिए n कदम उठाता है)। - दाईं ओर की सीट पर यात्रियों से कहें कि वे सामने वाले व्यक्ति से -1 बार स्वैप करें।

5 जब तक आप 3000 पाउंड तक नहीं पहुंचते, तब तक उन्हें बाहर निकाल दें।

यदि आपके पास वास्तव में पतला यात्री भार है तो 3 चरण + n चरण और 30 कदम।

दो गलियारे के लिए विमान - निर्देश अधिक जटिल हैं, लेकिन प्रदर्शन उसी के बारे में है।


लायर कोगन के जवाब के रूप में ही, लेकिन बहुत अधिक विस्तार से।
मूइंग डक

7
एक "अच्छा पर्याप्त" समाधान "मुफ्त हॉटडॉग" की पेशकश करना और सामने आने वाले पहले पंद्रह को बाहर फेंकना होगा। हर बार इष्टतम समाधान प्रदान नहीं करेगा लेकिन सादे "O" में चलता है।
जेम्स एंडरसन

क्या पिछले 15 को बाहर फेंकना बेहतर नहीं होगा क्योंकि भारी वाले शायद धीमे होंगे?
पीटर

@Patriker - मेरा मानना ​​है कि उद्देश्य न्यूनतम लोगों की संख्या के साथ 3000 पाउंड कम करना है। यद्यपि आप चरण 4 को "n - 29 बार से व्यक्ति के साथ स्वैप" करके एल्गोरिथ्म को अनुकूलित कर सकते थे, जो कि सामने वाले को 30 porkiest मिलेगा, हालांकि, वजन के सख्त क्रम में नहीं।
जेम्स एंडरसन

4

मैं शायद std::nth_elementरैखिक समय में 20 सबसे भारी लोगों को विभाजित करने के लिए उपयोग करूंगा । फिर आकाश के सबसे भारी को खोजने और टक्कर देने के लिए एक अधिक जटिल विधि का उपयोग करें।


3

आप औसत और मानक विचलन प्राप्त करने के लिए सूची में एक पास बना सकते हैं, फिर इसका उपयोग करें कि उन लोगों की संख्या को अनुमानित करें जिन्हें जाना है। उस संख्या के आधार पर सूची बनाने के लिए आंशिक_सॉर्ट का उपयोग करें। यदि अनुमान कम था, तो नए अनुमान के साथ शेष पर आंशिक रूप से फिर से उपयोग करें।



2

यहाँ पायथन के अंतर्निहित हीपैक मॉड्यूल का उपयोग करके एक ढेर-आधारित समाधान है। यह पायथन में है इसलिए मूल प्रश्न का उत्तर नहीं देता है, लेकिन यह अन्य पोस्ट किए गए पायथन समाधान की तुलना में क्लीनर (IMHO) है।

import itertools, heapq

# Test data
from collections import namedtuple

Passenger = namedtuple("Passenger", "name seat weight")

passengers = [Passenger(*p) for p in (
    ("Alpha", "1A", 200),
    ("Bravo", "2B", 800),
    ("Charlie", "3C", 400),
    ("Delta", "4A", 300),
    ("Echo", "5B", 100),
    ("Foxtrot", "6F", 100),
    ("Golf", "7E", 200),
    ("Hotel", "8D", 250),
    ("India", "8D", 250),
    ("Juliet", "9D", 450),
    ("Kilo", "10D", 125),
    ("Lima", "11E", 110),
    )]

# Find the heaviest passengers, so long as their
# total weight does not exceeed 3000

to_toss = []
total_weight = 0.0

for passenger in passengers:
    weight = passenger.weight
    total_weight += weight
    heapq.heappush(to_toss, (weight, passenger))

    while total_weight - to_toss[0][0] >= 3000:
        weight, repreived_passenger = heapq.heappop(to_toss)
        total_weight -= weight


if total_weight < 3000:
    # Not enough people!
    raise Exception("We're all going to die!")

# List the ones to toss. (Order doesn't matter.)

print "We can get rid of", total_weight, "pounds"
for weight, passenger in to_toss:
    print "Toss {p.name!r} in seat {p.seat} (weighs {p.weight} pounds)".format(p=passenger)

यदि k = यात्रियों की संख्या टॉस और N = यात्रियों की संख्या है, तो इस एल्गोरिथ्म के लिए सबसे अच्छा मामला O (N) है और इस एल्गोरिथम के लिए सबसे खराब स्थिति Nlog (N) है। सबसे खराब स्थिति तब होती है जब k लंबे समय तक N के पास होता है। यहाँ सबसे खराब कलाकारों का एक उदाहरण है:

weights = [2500] + [1/(2**n+0.0) for n in range(100000)] + [3000]

हालांकि, इस मामले में (लोगों को विमान से उतारना (पैराशूट के साथ, मुझे लगता है)) तो k को 3000 से कम होना चाहिए, जो कि << "लाखों लोग" हैं। औसत रनटाइम इसलिए Nlog (k) के बारे में होना चाहिए, जो लोगों की संख्या के लिए रैखिक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.