Αλγόριθμο για να βρείτε ποια αριθμού σε μια λίστα συνοψίσουμε σε έναν ορισμένο αριθμό

ψήφοι
20

Έχω μια λίστα με αριθμούς. Έχω επίσης ένα ορισμένο ποσό. Το ποσό είναι κατασκευασμένο από μερικούς αριθμούς από τη λίστα μου (μπορεί / δεν μπορεί να γνωρίζει πόσοι αριθμοί είναι κατασκευασμένο από). Είναι ένα γρήγορο αλγόριθμο για να πάρετε μια λίστα με τις πιθανές τους αριθμούς υπάρχουν; Γραμμένο σε Python θα είναι μεγάλη, αλλά ψευδο-κώδικα είναι πάρα πολύ καλό. (Δεν μπορώ ακόμα να διαβάσει οτιδήποτε άλλο εκτός από Python: P)

Παράδειγμα

list = [1,2,3,10]
sum = 12
result = [2,10]

ΣΗΜΕΙΩΣΗ: ξέρω από αλγόριθμο για να βρείτε τους αριθμούς από μια λίστα μεγέθους n κεφαλαίου σε άλλο αριθμό . (Αλλά δεν μπορώ να διαβάσω C # και είμαι σε θέση να ελέγξει εάν λειτουργεί για τις ανάγκες μου, είμαι σε Linux και προσπάθησα χρησιμοποιώντας Mono, αλλά παίρνω λάθη και δεν μπορώ να καταλάβω πώς να εργαστεί C # :(
κΑΙ ξέρω από αλγόριθμο για να συνοψίσουμε μια λίστα των αριθμών για όλους τους συνδυασμούς (αλλά φαίνεται να είναι αρκετά αναποτελεσματική. δεν χρειάζεται όλους τους συνδυασμούς .)

Δημοσιεύθηκε 06/08/2010 στις 05:09
πηγή χρήστη
Σε άλλες γλώσσες...                            


4 απαντήσεις

ψήφοι
33

Το πρόβλημα αυτό μειώνει στο πρόβλημα του σακιδίου 0-1 , όπου προσπαθείτε να βρείτε ένα σύνολο με ένα ακριβές ποσό. Η λύση εξαρτάται από τους περιορισμούς, στη γενική περίπτωση το πρόβλημα είναι NP-Complete.

Ωστόσο, εάν το μέγιστο ποσό αναζήτηση (ας το ονομάσουμε S) δεν είναι πολύ υψηλή, τότε μπορείτε να λύσετε το πρόβλημα με τη χρήση δυναμικού προγραμματισμού. Θα το εξηγήσω χρησιμοποιώντας μια αναδρομική συνάρτηση και memoization , η οποία είναι πιο εύκολο να καταλάβουμε από μια προσέγγιση από κάτω προς τα πάνω.

Ας κώδικα λειτουργία f(v, i, S), έτσι ώστε να επιστρέφει τον αριθμό των υποσυνόλων στο v[i:]ότι συνοψίζει ακριβώς S. Για να το λύσει αναδρομικά, πρώτα πρέπει να αναλύσουμε τη βάση (δηλαδή v[i:]είναι άδειο):

  • S == 0: Το μόνο υποσύνολο των []έχει αθροίσματος 0, έτσι είναι μια έγκυρη υποσύνολο. Εξαιτίας αυτού, η λειτουργία θα πρέπει να επιστρέψει 1.

  • S = 0: Ως το μόνο υποσύνολο []έχει ποσού 0, δεν υπάρχει έγκυρη υποσύνολο. Εξαιτίας αυτού, η λειτουργία θα πρέπει να επιστρέψει 0.

Στη συνέχεια, ας αναλύσουμε την αναδρομική περίπτωση (δηλαδή: v[i:]δεν είναι κενό). Υπάρχουν δύο επιλογές: να περιλαμβάνει τον αριθμό v[i]της τρέχουσας υποσύνολο, ή να μην το συμπεριλάβει. Αν συμπεριλάβουμε v[i], τότε ψάχνουμε υποσύνολα που έχουν άθροισμα S - v[i], αλλιώς, είμαστε ακόμα ψάχνουν για υποσύνολα με ποσό S. Η λειτουργία fμπορεί να εφαρμοστεί με τον ακόλουθο τρόπο:

def f(v, i, S):
  if i >= len(v): return 1 if S == 0 else 0
  count = f(v, i + 1, S)
  count += f(v, i + 1, S - v[i])
  return count

v = [1, 2, 3, 10]
sum = 12
print(f(v, 0, sum))

Με τον έλεγχο f(v, 0, S) > 0, μπορείτε να γνωρίζετε αν υπάρχει μια λύση στο πρόβλημά σας. Ωστόσο, αυτός ο κώδικας είναι πολύ αργή, κάθε αναδρομική κλήση γεννά δύο νέες κλήσεις, η οποία οδηγεί σε O (2 ^ n) αλγόριθμο. Τώρα, μπορούμε να εφαρμόσουμε memoization για να τρέξει σε χρόνο O (n * S), η οποία είναι ταχύτερη, εάν Sδεν είναι πολύ μεγάλο:

def f(v, i, S, memo):
  if i >= len(v): return 1 if S == 0 else 0
  if (i, S) not in memo:  # <-- Check if value has not been calculated.
    count = f(v, i + 1, S, memo)
    count += f(v, i + 1, S - v[i], memo)
    memo[(i, S)] = count  # <-- Memoize calculated result.
  return memo[(i, S)]     # <-- Return memoized value.

v = [1, 2, 3, 10]
sum = 12
memo = dict()
print(f(v, 0, sum, memo))

Τώρα, είναι δυνατόν να κωδικοποιήσει μια συνάρτηση gπου επιστρέφει ένα υποσύνολο που συνοψίζει S. Για να γίνει αυτό, αρκεί να προσθέσετε στοιχεία μόνο αν υπάρχει τουλάχιστον μια λύση, συμπεριλαμβανομένων αυτών:

def f(v, i, S, memo):
  # ... same as before ...

def g(v, S, memo):
  subset = []
  for i, x in enumerate(v):
    # Check if there is still a solution if we include v[i]
    if f(v, i + 1, S - x, memo) > 0:
      subset.append(x)
      S -= x
  return subset

v = [1, 2, 3, 10]
sum = 12
memo = dict()
if f(v, 0, sum, memo) == 0: print("There are no valid subsets.")
else: print(g(v, sum, memo))

Αποκήρυξη: Αυτό το διάλυμα λέει ότι υπάρχουν δύο υποσύνολα [10, 10] που συνοψίζει το 10. Αυτό είναι διότι υποθέτει ότι η πρώτη δέκα είναι διαφορετική στο δεύτερο δέκα. Ο αλγόριθμος μπορεί να καθοριστεί να υποθέσουμε ότι και οι δύο δεκάδες είναι ίσα (και ως εκ τούτου να απαντήσει ένα), αλλά αυτό είναι λίγο πιο περίπλοκη.

Απαντήθηκε 06/08/2010 στις 06:16
πηγή χρήστη

ψήφοι
1

Έτσι, η λογική είναι να αντιστραφεί το είδος τους αριθμούς, και ας υποθέσουμε ότι ο κατάλογος των αριθμών l και ποσό που πρόκειται να σχηματιστεί είναι s .

   for i in b:
            if(a(round(n-i,2),b[b.index(i)+1:])):
                r.append(i)    
                return True
        return False

Στη συνέχεια, περνάμε μέσα από αυτό το βρόχο και ένας αριθμός επιλέγεται από l σε σειρά και ας λένε ότι είναι i . υπάρχουν 2 πιθανές περιπτώσεις είτε i είναι το μέρος του ποσού ή όχι. Έτσι, υποθέτουμε ότι i είναι μέρος της λύσης και, στη συνέχεια, το πρόβλημα μειώνει σε l ον l[l.index(i+1):]και s ον si έτσι, εάν η λειτουργία μας είναι (l, s), τότε λέμε a(l[l.index(i+1):] ,s-i). και αν εγώ δεν αποτελεί μέρος του s τότε θα πρέπει να σχηματίσουν s από τη l[l.index(i+1):]λίστα. Έτσι είναι παρόμοια και στις δύο περιπτώσεις, μόνο η αλλαγή είναι αν μπορώ να αποτελεί μέρος του s, τότε s = si και τα άλλα s = s μόνο.

τώρα για να μειώσει το πρόβλημα έτσι ώστε σε αριθμούς περίπτωση l είναι μεγαλύτερες από ό, τι s να τους αφαιρέσει για να μειωθεί η πολυπλοκότητα μέχρι l είναι άδειο και σε αυτή την περίπτωση οι αριθμοί που επιλέγονται δεν αποτελούν μέρος της λύσης μας και επιστρέφουμε ψευδείς.

if(len(b)==0):
    return False    
while(b[0]>n):
    b.remove(b[0])
    if(len(b)==0):
        return False    

και σε περίπτωση ιβ έχει μόνο 1 στοιχείο αριστερά, στη συνέχεια, είτε μπορεί να είναι μέρος του s τότε θα επιστρέψει αλήθεια ή δεν είναι, τότε return false και βρόχο θα περάσουν από άλλο αριθμό.

if(b[0]==n):
    r.append(b[0])
    return True
if(len(b)==1):
    return False

Σημειώστε στο βρόχο αν έχουν χρησιμοποιηθεί b..but b είναι η λίστα μας only.and έχω στρογγυλεμένες όπου αυτό είναι δυνατό, έτσι ώστε να μην πρέπει να πάρετε λάθος απάντηση, λόγω των κυμαινόμενων υπολογισμούς σημείο python.

r=[]
list_of_numbers=[61.12,13.11,100.12,12.32,200,60.00,145.34,14.22,100.21,14.77,214.35,200.32,65.43,0.49,132.13,143.21,156.34,11.32,12.34,15.67,17.89,21.23,14.21,12,122,134]
list_of_numbers=sorted(list_of_numbers)
list_of_numbers.reverse()
sum_to_be_formed=401.54
def a(n,b):
    global r
    if(len(b)==0):
        return False    
    while(b[0]>n):
        b.remove(b[0])
        if(len(b)==0):
            return False    
    if(b[0]==n):
        r.append(b[0])
        return True
    if(len(b)==1):
        return False
    for i in b:
        if(a(round(n-i,2),b[b.index(i)+1:])):
            r.append(i)    
            return True
    return False
if(a(sum_to_be_formed,list_of_numbers)):
    print(r)

η λύση αυτή λειτουργεί fast.more γρήγορα από ό, τι εκείνη που περιγράφεται παραπάνω. Ωστόσο, αυτό λειτουργεί μόνο για θετικούς αριθμούς. Ωστόσο, επίσης, λειτουργεί καλά, αν υπάρχει μια λύση μόνο με άλλο τρόπο παίρνει πολύ χρόνο για να βγούμε από βρόχους.

ένα παράδειγμα τρέξιμο είναι σαν αυτό ας πούμε

    l=[1,6,7,8,10]

and s=22 i.e. s=1+6+7+8
so it goes through like this 

1.) [10, 8, 7, 6, 1] 22
i.e. 10  is selected to be part of 22..so s=22-10=12 and l=l.remove(10)
2.) [8, 7, 6, 1] 12
i.e. 8  is selected to be part of 12..so s=12-8=4 and l=l.remove(8)
3.) [7, 6, 1] 4  
now 7,6 are removed and 1!=4 so it will return false for this execution where 8 is selected.
4.)[6, 1] 5
i.e. 7  is selected to be part of 12..so s=12-7=5 and l=l.remove(7)
now 6 are removed and 1!=5 so it will return false for this execution where 7 is selected.
5.)[1] 6
i.e. 6  is selected to be part of 12..so s=12-6=6 and l=l.remove(6)
now 1!=6 so it will return false for this execution where 6 is selected.
6.)[] 11
i.e. 1 is selected to be part of 12..so s=12-1=1 and l=l.remove(1)
now l is empty so all the cases for which 10 was a part of s are false and so 10 is not a part of s and we now start with 8 and same cases follow.
7.)[7, 6, 1] 14
8.)[6, 1] 7
9.)[1] 1

ακριβώς για να δώσει μια σύγκριση που έτρεξα στον υπολογιστή μου που δεν είναι τόσο καλή. χρησιμοποιώντας

l=[61.12,13.11,100.12,12.32,200,60.00,145.34,14.22,100.21,14.77,214.35,145.21,123.56,11.90,200.32,65.43,0.49,132.13,143.21,156.34,11.32,12.34,15.67,17.89,21.23,14.21,12,122,134]

και

s = 2000

βρόχος μου έτρεξε 1018 φορές και 31 ms.

και τα προηγούμενα κωδικό βρόχο έτρεξε 3415587 φορές και πήρε κάπου κοντά 16 δευτερόλεπτα.

Ωστόσο, σε περίπτωση που δεν υπάρχει λύση κωδικό μου έτρεξε περισσότερο από μερικά λεπτά, γι 'αυτό σταμάτησε και η προηγούμενη κωδικό έτρεξε μόνο κοντά περίπου 17 ms και τα προηγούμενα κωδικός λειτουργεί με αρνητικούς αριθμούς επίσης.

γι 'αυτό το πράγμα κάποιες βελτιώσεις μπορούν να γίνουν.

Απαντήθηκε 24/12/2015 στις 19:29
πηγή χρήστη

ψήφοι
0
#!/usr/bin/python2

ylist = [1, 2, 3, 4, 5, 6, 7, 9, 2, 5, 3, -1]
print ylist 
target = int(raw_input("enter the target number")) 
for i in xrange(len(ylist)):
    sno = target-ylist[i]
    for j in xrange(i+1, len(ylist)):
        if ylist[j] == sno:
            print ylist[i], ylist[j]

Αυτός ο κωδικός python κάνει ό, τι ζητήσατε, θα εκτυπώσει το μοναδικό ζεύγος των αριθμών των οποίων το άθροισμα είναι ίσο με το μεταβλητό στόχο.

αν ο αριθμός-στόχος είναι 8, θα εκτυπώσει: 
1 7
2 6
3 5
3 5
5 3
6 2
9 -1
5 3
Απαντήθηκε 08/02/2017 στις 04:38
πηγή χρήστη

ψήφοι
0

Έχω βρει απάντηση η οποία έχει τρέξει-χρονική πολυπλοκότητα O (n) και χωρική πολυπλοκότητα περίπου O (2n), όπου το η είναι το μήκος της λίστας.

Η απάντηση ικανοποιεί τους ακόλουθους περιορισμούς:

  1. Λίστα μπορούν να περιέχουν αντίγραφα, π.χ. [1,1,1,2,3] και θέλετε να βρείτε ζεύγη συνοψίσω σε 2

  2. Λίστα μπορούν να περιέχουν τόσο θετικές όσο και αρνητικές ακέραιοι

Ο κώδικας είναι όπως παρακάτω, και που ακολουθείται από την εξήγηση:

def countPairs(k, a):
    # List a, sum is k
    temp = dict()
    count = 0
    for iter1 in a:
        temp[iter1] = 0
        temp[k-iter1] = 0
    for iter2 in a:
        temp[iter2] += 1
    for iter3 in list(temp.keys()):
        if iter3 == k / 2 and temp[iter3] > 1:
            count += temp[iter3] * (temp[k-iter3] - 1) / 2
        elif iter3 == k / 2 and temp[iter3] <= 1:
            continue
        else:
            count += temp[iter3] * temp[k-iter3] / 2
    return int(count)
  1. Δημιουργήστε ένα άδειο λεξικό, μετακινηθείτε μέσα στη λίστα και να θέσει όλα τα πιθανά κλειδιά στο dict με αρχική τιμή 0. Σημειώστε ότι το κλειδί (k-ITER1) Είναι αναγκαίο να διευκρινιστεί, π.χ. αν η λίστα περιέχει 1 αλλά δεν περιέχει 4, και το άθροισμα είναι 5. στη συνέχεια, όταν κοιτάξουμε 1, θα θέλαμε να βρούμε πόσες 4 έχουμε, αλλά αν 4 δεν είναι στην dict, τότε θα αυξήσει σφάλμα.
  2. Επαναλάβει τη λίστα και πάλι, και μετρήστε πόσες φορές που εμφανίζεται κάθε ακέραιο και να αποθηκεύουν τα αποτελέσματα στην dict.
  3. Επαναλάβει μέσα από μέσα από το dict, αυτή τη φορά είναι να βρείτε πόσα ζευγάρια εμείς έχουμε. Πρέπει να εξετάσουμε 3 προϋποθέσεις:

    3.1 Το κλειδί είναι ακριβώς το μισό του ποσού και το πλήκτρο αυτό εμφανίζεται περισσότερες από μία φορές στη λίστα, π.χ. κατάλογος είναι [1,1,1], ποσό που είναι 2 Αντιμετωπίζουμε αυτό το ιδιαίτερο και τι κάνει ο κώδικας.

    3.2 Το κλειδί είναι ακριβώς το μισό του ποσού και το πλήκτρο αυτό εμφανίζεται μόνο μία φορά στη λίστα, παραλείψτε αυτή την κατάσταση.

    3.3 Για τις άλλες περιπτώσεις που το κλειδί δεν είναι το ήμισυ του ποσού, απλά πολλαπλασιάστε την αξία του σε σχέση με την αξία ενός άλλου κλειδιού, όπου αυτά τα δύο κλειδιά συνοψίσω στη δοσμένη τιμή. Π.χ. Αν το ποσό είναι 6, πολλαπλασιάζουμε θερμοκρασία [1] και η θερμοκρασία [5], θερμοκρασία [2] και η θερμοκρασία [4], κλπ ... (δεν είχα λίστα περιπτώσεις όπου οι αριθμοί είναι αρνητικά, αλλά η ιδέα είναι η ίδια. )

Το πιο πολύπλοκο βήμα είναι το βήμα 3, η οποία περιλαμβάνει την αναζήτηση στο λεξικό, αλλά όπως η αναζήτηση στο λεξικό είναι συνήθως γρήγορη, σχεδόν σταθερή πολυπλοκότητα. (Αν χειρότερη περίπτωση είναι O (n), αλλά δεν πρέπει να συμβεί για τα κλειδιά ακέραιο.) Έτσι, με την παραδοχή ότι η αναζήτηση είναι σταθερή πολυπλοκότητα, η συνολική πολυπλοκότητα είναι O (n) όπως επαναλάβει μόνο τη λίστα πολλές φορές ξεχωριστά.

Συμβουλές για μια καλύτερη λύση είναι ευπρόσδεκτη :)

Απαντήθηκε 08/10/2017 στις 09:30
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more