एक क्षेत्र के आधार पर वस्तुओं की एक बड़ी सूची का सबसे कुशल संयोजन प्राप्त करें


9

मैं संयोजन पर एक निश्चित बजट और अधिकतम सीमा दिए गए सितारों की संख्या को अधिकतम करने के लिए देख रहा हूं।

उदाहरण प्रश्न:

500 यूरो के बजट के साथ, केवल अधिकतम अनुमत रेस्तरां या उससे कम, भोजन करें और सबसे अधिक संभव सितारों को इकट्ठा करें।

मैं एक कुशल एल्गोरिथ्म लिखना चाह रहा हूं, जो 10 अधिकतम रेस्तरां के लिए संभावित रूप से 1 मिलियन रेस्तरां उदाहरणों को संसाधित कर सकता है।

ध्यान दें, यह एक प्रश्न है जो मैंने कल पूछा था: क्रॉस: एक क्षेत्र पर आधारित वस्तुओं की एक बड़ी सूची का सबसे कुशल संयोजन प्राप्त करें

नीचे दिए गए समाधान r8रेस्तरां को 15 डॉलर प्रति स्टार प्रदान करेंगे , जिसका अर्थ है कि सूची बनाते समय, यह सूची में पहले स्थान पर रखता है, और शेष 70 डॉलर के साथ कुल 4 सितारों को देने वाले केवल 2 और सितारों को प्राप्त कर सकता है। हालांकि, अगर यह r8रेस्तरां को छोड़ने के लिए पर्याप्त स्मार्ट था (भले ही यह प्रति स्टार अनुपात में सबसे अच्छा डॉलर हो) तो r1रेस्तरां वास्तव में बजट के लिए एक बेहतर विकल्प होगा, क्योंकि यह $ 100 लागत और 5 स्टार है।

किसी को भी समस्या का प्रयास और वर्तमान समाधान को हरा सकते हैं?

import itertools

class Restaurant():
  def __init__(self, cost, stars):
    self.cost = cost
    self.stars = stars
    self.ratio = cost / stars

  def display(self):
    print("Cost: $" + str(self.cost))
    print("Stars: " + str(self.stars))
    print()

r1 = Restaurant(100, 5)
r2 = Restaurant(140, 3)
r3 = Restaurant(90, 4)
r4 = Restaurant(140, 3)
r5 = Restaurant(120, 4)
r6 = Restaurant(60, 1)
r7 = Restaurant(40, 1)
r8 = Restaurant(30, 2)
r9 = Restaurant(70, 2)
r10 = Restaurant(250, 5)

print()
print("***************")
print("** Unsorted: **")
print("***************")
print()

restaurants = [r1, r2, r3, r4, r5, r6, r7, r8, r9, r10]

for restaurant in restaurants:
  print(restaurant.ratio, restaurant.stars)

print()
print("***************")
print("**  Sorted:  **")
print("***************")
print()

sorted_restaurants = sorted(restaurants, key = lambda x: x.ratio, reverse = True)

for restaurant in sorted_restaurants:
  print(restaurant.ratio, restaurant.stars)

print()
print("*********************")
print("** Begin Rucksack: **")
print("*********************")
print()

max = 5
budget = 100

spent = 0
quantity = 0

rucksack = []

for i in itertools.count():

  if len(rucksack) >= max or i == len(sorted_restaurants):
    break

  sorted_restaurants[i].display()

  if sorted_restaurants[i].cost + spent <= budget:
    spent = spent + sorted_restaurants[i].cost
    rucksack.append(sorted_restaurants[i])

print("Total Cost: $" + str(sum([x.cost for x in rucksack])))
print("Total Stars: " + str(sum([x.stars for x in rucksack])))

print()
print("*****************")
print("** Final List: **")
print("*****************")
print()

for restaurant in rucksack:
  restaurant.display()

2
क्या यह नोकझोंक है? मुझे माफ कर दो, मैंने स्किम किया।
केनी ओस्ट्रोम

1
यह नैकपैक की एक ही अवधारणा है - budget= किग्रा में अधिकतम रूकसाक वजन, max= आइटम की संख्या जो दस्ता रख सकती है, stars= आइटम पर कुछ मूल्य और costकिलो में आइटम का वजन
AK47

3
और कोड के साथ समस्या क्या है?
OneCricketeer

1
@ क्रिकेट_007 ऑर्डर के आधार पर, यह r8रेस्तरां को 15 डॉलर प्रति स्टार प्रदान करता है , जिसका अर्थ है कि सूची बनाते समय, यह सूची में पहले स्थान पर रखता है, और शेष 70 डॉलर के साथ इसे केवल 2 और सितारे मिल सकते हैं। हालाँकि, अगर यह स्मार्ट को छोड़ दिया जाए (भले ही यह प्रति स्टार अनुपात में सबसे अच्छा डॉलर हो, तो r1रेस्तरां वास्तव में बजट के लिए बेहतर विकल्प होगा, क्योंकि यह $ 100 लागत और 5 स्टार है
AK47

जवाबों:


5

लगता है कि आपकी समस्या नैकपैक समस्या के समान है: अधिकतम मान कुछ वजन और मात्रा की कमी को देखते हुए। मूल रूप से = कुल सितारे, वजन = मूल्य, रूकसाक सीमा = कुल बजट। अब कुल "वस्तुओं" (रेस्तरां का दौरा) का एक अतिरिक्त बाधा है, लेकिन यह परिवर्तन नहीं करता है।

जैसा कि आप जानते हैं या नहीं जान सकते हैं, नैकपैक की समस्या एनपी कठिन है, जिसका अर्थ है कि बहुपद समय स्केलिंग के साथ कोई एल्गोरिथ्म नहीं जाना जाता है।

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

गतिशील प्रोग्रामिंग दृष्टिकोण यहाँ बहुत अच्छा होना चाहिए। यह एक पुनरावृत्ति पर आधारित है: एक बजट बी और कई शेष विज़िट वी को देखते हुए, रेस्तरां आर के कुल सेट से बाहर जाने के लिए रेस्तरां का सबसे अच्छा सेट क्या है?

यहां देखें: https://en.wikipedia.org/wiki/Knapsack_problem#0/1_knapsack_problem

मूल रूप से हम m"अधिकतम सितारों" के लिए एक सरणी को परिभाषित करते हैं , जहां m[i, b, v]हम सितारों की अधिकतम राशि प्राप्त कर सकते हैं, जब हमें रेस्तरां में (और) सहित रेस्तरां में जाने i, अधिकतम खर्च करने bऔर अधिकांश vरेस्तरां (सीमा) पर जाने की अनुमति होती है ।

अब, हम नीचे-ऊपर इस सरणी को भरते हैं। उदाहरण के लिए, m[0, b, v] = 0सभी मूल्यों के लिए bऔर vक्योंकि अगर हम किसी भी रेस्तरां में नहीं जा सकते हैं, तो हमें कोई स्टार नहीं मिल सकता है।

इसके अलावा, m[i, b, 0] = 0सभी मूल्यों के लिए iऔर bक्योंकि यदि हमने अपनी सभी यात्राओं का उपयोग किया है, तो हमें और अधिक सितारे नहीं मिल सकते हैं।

अगली पंक्ति या तो बहुत कठिन नहीं है:

m[i, b, v] = m[i - 1, b, v] if p[i] > b जहां p[i]रेस्तरां में खाने की कीमत है i। यह पंक्ति क्या कहती है? ठीक है, अगर iहमारे पास बचे पैसे ( b) से ज्यादा महंगे हैं तो हम वहां नहीं जा सकते। जिसका अर्थ है कि हम जितने सितारों को प्राप्त कर सकते हैं, उतने ही हैं, चाहे हम रेस्तरां को शामिल करें iया सिर्फ ऊपर i - 1

अगली पंक्ति थोड़ी मुश्किल है:

m[i, b, v] = max(m[i-1, b, v]), m[i-1, b - p[i], v-1] + s[i]) if p[i] <= b

ओह। s[i]रेस्तरां ibtw से आपको मिलने वाले सितारों की मात्रा है ।

यह पंक्ति क्या कहती है? यह गतिशील प्रोग्रामिंग दृष्टिकोण का दिल है। सितारों की अधिकतम मात्रा पर विचार करते समय जब हम रेस्तरां को देख सकते हैं और शामिल कर सकते हैं i, तो परिणामस्वरूप समाधान में हम या तो वहां जाते हैं या हम नहीं करते हैं, और हमें "बस" देखना होगा कि इन दोनों रास्तों में से कौन अधिक है सितारे:

यदि हम रेस्तरां में नहीं जाते हैं i, तो हम उतने ही पैसे और शेष यात्राएं करते हैं। इस पथ में हम प्राप्त कर सकते हैं सितारों की अधिकतम राशि के रूप में ही है अगर हम भी रेस्तरां में नहीं देखा था i। यही कारण है कि में पहले भाग है max

लेकिन अगर हम रेस्तरां में जाते हैं i, तो हम p[i]कम पैसे, एक कम यात्रा और s[i]अधिक सितारों के साथ रह जाते हैं। वह दूसरा भाग है max

अब सवाल सरल है: दोनों में से कौन बड़ा है।

आप इस सरणी को बना सकते हैं और इसे लूप के लिए अपेक्षाकृत सरल बना सकते हैं (विकी से प्रेरणा लें)। यह आपको केवल सितारों की राशि देता है, न कि रेस्तरां की वास्तविक सूची पर जाएँ। उसके लिए, गणना करने के लिए कुछ अतिरिक्त बहीखाता जोड़ें w


मुझे आशा है कि जानकारी आपको सही दिशा में स्थापित करने के लिए पर्याप्त है।

वैकल्पिक रूप से, आप बाइनरी वैरिएबल और एक द्विघात उद्देश्य फ़ंक्शन के संदर्भ में अपनी समस्या लिख ​​सकते हैं और इसे डी-वेव क्वांटम एनेलेर पर हल कर सकते हैं: - यदि आप इसके बारे में अधिक जानना चाहते हैं तो मुझे संदेश भेजें।


बहुपद समय के बारे में, अधिकतम 10 रेस्तरां का मतलब है कि समस्या को ब्रूट बल द्वारा हल किया जा सकता है, 10 रेस्तरां तक ​​के सभी संयोजनों के माध्यम से पुनरावृत्ति, और ओ (एन ^ 10) समय में सबसे अच्छा रखते हुए। अब, मैं n = 10 ^ 6 के साथ एक O (n ^ 10) एल्गोरिथ्म चलाना नहीं चाहता, लेकिन यह बहुपद समय है।
काया 3

क्या "10 रेस्तरां" वास्तव में एक निश्चित संख्या है, या सिर्फ उपरोक्त उदाहरण में तय किया गया है, और एक अलग उदाहरण के लिए बड़ा हो सकता है?
लैगरबैर

यह एक अच्छा सवाल है, और यह स्पष्ट नहीं है कि समस्या के कौन से पैरामीटर चल रहे समय का विश्लेषण करते समय सामान्यीकृत किए जाते हैं। बेशक, इसका कोई ज्ञात समाधान नहीं है जो कि k में बहुपद है, मेरा मतलब है कि यह काफी कमजोर निष्कर्ष है यदि हम केवल छोटी k की समस्या में रुचि रखते हैं।
काया 3

"अधिकतम" रेस्तरां की संख्या बदल सकती है। यह पुनरावृत्ति 10 हो सकती है, और इसके बाद यह 5 हो सकती है
AK47

@ AK47 भले ही, मैं ऊपर स्केच किया एल्गोरिथ्म बहुत साफ होना चाहिए। बहुआयामी सरणी का आकार आपके बजट, रेस्तरां की संख्या और विज़िट की संख्या के द्वारा दिया जाता है, और सरणी की एक प्रविष्टि में भरने के लिए O (1) लेता है, इसलिए समय में ओ (R) चलता है बी वी)।
लेगैरबेर

2

यहाँ मेरे उत्तर के समान विचार का उपयोग करना :

S को योग करने वाले n धनात्मक संख्याओं के संग्रह में, उनमें से कम से कम एक n (S / n) से विभाजित S से कम होगा।

आप संभावित "सबसे सस्ते" रेस्तरां से शुरू होने वाली सूची का निर्माण कर सकते हैं

एल्गोरिथ्म के चरण:

  • ५०० रेस्तरां के साथ लागत का पता लगाएं <५०० / १०, प्रत्येक अलग-अलग सितारों के साथ और प्रत्येक स्टार के लिए सबसे कम लागत । जैसे r1, r2, r3, r4, r5
  • उपरोक्त मूल्यों में से प्रत्येक के लिए, लागत <(500 - लागत (x)) / 9 और विभिन्न सितारों के साथ एक और 5 रेस्तरां खोजें । फिर से प्रत्येक स्टार के लिए सबसे कम लागत का चयन करें
  • ऐसा तब तक करें जब तक आप 10 रेस्तराँ में पहुँच जाएँ और आप अपने बजट से अधिक न हों
  • 1 - 9 रेस्तरां सीमा के लिए ऊपर के 3 चरणों को फिर से चलाएँ।
  • सबसे सितारों का उत्पादन करने वाले समाधान रखें

बेशक, आप एक रेस्तरां का आकार नहीं बदल सकते।

मुझे लगता है कि सबसे खराब स्थिति, आपको 5x5x5 ... = 5 ^ 10 + 5 ^ 9 + ... + 5 ^ 2 + 5 (= लगभग 12 मिलियन) समाधानों की गणना करनी होगी।

जावास्क्रिप्ट में

function Restaurant(name, cost, stars) {
    this.name = name;
    this.cost = cost;
    this.stars = stars;
}

function RestaurantCollection() {
    var restaurants = [];
    var cost = 0;
    this.stars = 0;

    this.addRestaurant = function(restaurant) {
        restaurants.push(restaurant);
        cost += restaurant.cost;
        this.stars += restaurant.stars;
    };

    this.setRestaurants = function(clonedRestaurants, nCost, nStars) {
        restaurants = clonedRestaurants;
        cost = nCost;
        this.stars += nStars;
    };
    this.getAll = function() {
        return restaurants;
    };

    this.getCost = function() {
        return cost;
    };
    this.setCost = function(clonedCost) {
        cost = clonedCost;
    };

    this.findNext5Restaurants = function(restaurants, budget, totalGoal) {
        var existingRestaurants = this.getAll();
        var maxCost = (budget - cost) / (totalGoal - existingRestaurants.length);
        var cheapestRestaurantPerStarRating = [];
        for(var stars = 5; stars > 0; stars--) {
            var found = findCheapestRestaurant(restaurants, stars, maxCost, existingRestaurants);
            if(found) {
                cheapestRestaurantPerStarRating.push(found);
            }
        }
        return cheapestRestaurantPerStarRating;
    };

    this.clone = function() {
        var restaurantCollection = new RestaurantCollection();
        restaurantCollection.setRestaurants([...restaurants], this.getCost(), this.stars);
        return restaurantCollection;
    };
}

function findCheapestRestaurant(restaurants, stars, maxCost, excludeRestaurants) {
     var excludeRestaurantNames = excludeRestaurants.map(restaurant => restaurant.name);
     var found = restaurants.find(restaurant => restaurant.stars == stars && restaurant.cost <= maxCost && !excludeRestaurantNames.includes(restaurant.name));
     return found;
}

function calculateNextCollections(restaurants, collections, budget, totalGoal) {
    var newCollections = [];
    collections.forEach(collection => {
        var nextRestaurants = collection.findNext5Restaurants(restaurants, budget, totalGoal);
        nextRestaurants.forEach(restaurant => {
            var newCollection = collection.clone();
            newCollection.addRestaurant(restaurant);
            if(newCollection.getCost() <= budget) {
                 newCollections.push(newCollection);
            }
        });
    });
    return newCollections;
};

var restaurants = [];
restaurants.push(new Restaurant('r1', 100, 5));
restaurants.push(new Restaurant('r2',140, 3));
restaurants.push(new Restaurant('r3',90, 4));
restaurants.push(new Restaurant('r4',140, 3));
restaurants.push(new Restaurant('r5',120, 4));
restaurants.push(new Restaurant('r6',60, 1));
restaurants.push(new Restaurant('r7',40, 1));
restaurants.push(new Restaurant('r8',30, 2));
restaurants.push(new Restaurant('r9',70, 2));
restaurants.push(new Restaurant('r10',250, 5));

restaurants.sort((a, b) => a.cost - b.cost);
var max = 5;
var budget = 100;

var total = max;
var totalCollections = [];

for(var totalGoal = total; totalGoal > 0; totalGoal--) {
    var collections = [new RestaurantCollection()];

    for(var i = totalGoal; i > 0; i--) {
        collections = calculateNextCollections(restaurants, collections, budget, totalGoal);
    }
    totalCollections = totalCollections.concat(collections);
}

var totalCollections = totalCollections.map(collection => { 
      return {
          name: collection.getAll().map(restaurant => restaurant.name),
          stars: collection.stars,
          cost: collection.getCost()
      }
});

console.log("Solutions found:\n");
console.log(totalCollections);

totalCollections.sort((a, b) => b.stars - a.stars);
console.log("Best solution:\n");
console.log(totalCollections[0]);


हे @ जेंस बोटिस, यह 100000 रेस्तरां के लिए 27 सेकंड ले रहा है: repl.it/repls/StripedMoralOptimization क्या आपको लगता है कि इसे 1 मिलियन रिकॉर्ड के साथ काम करना संभव है?
AK47

अड़चन है। फाइलेटर () फंक्शन FindCheapestRestaurant () के अंदर, आप रेस्टोरेंट बनाने के बाद उसकी लागत को छाँट सकते हैं और उपयोग कर सकते हैं। फ़िल्टर के बजाय .find () के बाद से केवल 1 पाया गया सबसे सस्ता होगा। मैंने लिंक में बदलाव किया। लेकिन मुझे लगता है कि लागत पर एक सूचकांक के साथ रेस्तरां के लिए डेटाबेस (जैसे mysql) का उपयोग करना सबसे अच्छा समाधान होगा, इसलिए आप सशर्त चयन के साथ .filter () को बदल सकते हैं।
Jannes Botis
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.