Fractional Knapsack Problem: girig algoritm med exempel

โšก Smart sammanfattning

Fraktionellt ryggsรคcksproblem anvรคnder en girig algoritm som sorterar paket efter vรคrde-till-vikt-fรถrhรฅllande och tar artiklar i den ordningen, vilket gรถr att brรฅkdelar av artiklarna kan fylla รฅterstรฅende kapacitet fรถr en garanterat optimal lรถsning.

  • ???? Girig strategi: Lokala optimala val gรถrs i varje steg i hopp om att nรฅ ett globalt optimalt fรถr det รถvergripande problemet.
  • โš–๏ธ Vรคrde/viktfรถrhรฅllande: Paket sorteras i fallande ordning efter enhetskostnad V[i] / W[i] innan urvalet bรถrjar.
  • ๐Ÿ“ฆ Brรฅkregel: En del av nรคsta paket fyller eventuell รถverbliven kapacitet, vilket garanterar en optimal lรถsning fรถr den brรฅkdelsvarianten.
  • โฑ๏ธ Komplexitet: O(n log n) med snabb sortering eller sammanslagningssortering, dominerat av sorteringssteget snarare รคn urvalsslingan.
  • ???? Begrรคnsning: Samma giriga regel misslyckas pรฅ 0/1 Knapsack dรคr fรถremรฅl inte kan delas, sรฅ dynamisk programmering anvรคnds istรคllet.
  • ๐Ÿš€ Anvรคndningsomrรฅden: Lastning, portfรถljallokering, delning av molnbandbredd och AI-resursplanering รคr alla beroende av Fractional Knapsack.

Fraktionellt ryggsรคcksproblem, girig algoritm

Vad รคr Greedy Strategy?

Giriga algoritmer Vรคlj det bรคsta lokala valet i varje steg i hopp om att en kedja av lokala optima producerar en globalt optimal lรถsning. Liksom dynamisk programmering riktar de in sig pรฅ optimeringsproblem, men de ser aldrig tillbaka fรถr att omprรถva tidigare beslut.

Giriga algoritmer รคr vanligtvis enkla att skriva, snabba (ofta linjรคr eller kvadratisk tid), lรคtta att felsรถka och krรคver lite minne. Nackdelen รคr att resultatet inte alltid รคr optimalt, sรฅ strategin fungerar bara fรถr problem som har en bevisad girig-sรคker struktur.

Giriga strategier lรถser kombinatorisk optimering genom att bygga en lรถsning A, en komponent av AI i taget. Vid varje steg vรคljer du AI optimalt under de rรฅdande begrรคnsningarna och krymper problemet till ett mindre delproblem.

Tvรฅ egenskaper mรฅste gรคlla fรถr att en girig metod ska vara korrekt:

  1. Girigt val egendom: Ett lokalt optimum i varje steg leder till ett globalt optimum. Valet beror pรฅ tidigare beslut men inte pรฅ framtida.
  2. Optimal underkonstruktion: Den optimala lรถsningen av hela problemet innehรฅller optimala lรถsningar av dess delproblem.

En girig algoritm har fem komponenter:

  1. En kandidatuppsรคttning frรฅn vilken lรถsningar byggs.
  2. En urvalsfunktion som vรคljer den bรคsta nรคsta kandidaten.
  3. En genomfรถrbarhetsfunktion som kontrollerar om en kandidat kan utรถka den aktuella partiella lรถsningen.
  4. En objektivfunktion som vรคrderar en fullstรคndig eller partiell lรถsning.
  5. En utvรคrderingsfunktion som signalerar nรคr lรถsningen รคr klar.

Idรฉn om girig

Greedy One sorterar paket enbart efter vรคrde:

  • Sortera paket i icke-stigande vรคrdeordning.
  • Gรฅ igenom den sorterade listan och lรคgg varje paket i ryggsรคcken om den รฅterstรฅende kapaciteten rymmer det.

Denna regel ger inte alltid det optimala svaret. Motexempel:

  • Parametrar: n = 3, M = 19.
  • Paket: {i = 1; W = 14; V = 20}, {i = 2; W = 6; V = 16}, {i = 3; W = 10; V = 8} โ€” hรถgt vรคrde men ocksรฅ hรถg vikt.
  • Den girige vรคljer paket 1 med ett totalt vรคrde pรฅ 20, medan det optimala valet (paket 2, paket 3) nรฅr 24.

Idรฉn om giriga tvรฅ

Greedy Two sorterar paket enbart efter vikt:

  • Sortera paketen i icke-fallande viktordning.
  • Gรฅ igenom den sorterade listan och lรคgg varje paket i ryggsรคcken om den รฅterstรฅende kapaciteten rymmer det.

Denna regel misslyckas ocksรฅ med att vara optimal. Motexempel:

  • Parametrar: n = 3, M = 11.
  • Paket: {i = 1; W = 5; V = 10}, {i = 2; W = 6; V = 16}, {i = 3; W = 10; V = 28} โ€” lรฅg vikt men lรฅgt vรคrde.
  • Giriga Tvรฅ val (paket 1, paket 2) med totalt vรคrde 26, medan det optimala valet (paket 3) nรฅr 28.

Idรฉn om giriga tre

Greedy Three รฅtgรคrdar bรฅda felen genom att kombinera vรคrde och vikt i en enda rangordningsnyckel. Det รคr standardmetoden fรถr det brรฅkdelsbaserade ryggsรคcksproblemet.

  • Berรคkna enhetskostnaden V[i] / W[i] fรถr varje paket.
  • Sortera paket i icke-stigande ordning efter enhetskostnad.
  • Gรฅ igenom den sorterade listan och lรคgg till varje paket om den รฅterstรฅende kapaciteten rymmer det.

Greedy Three sortera efter enhetskostnad

Giriga Tre sorteringar efter enhetskostnad V[i] / W[i]

Idรฉ: Berรคkna vikt-vรคrde-fรถrhรฅllandet V[i] / W[i] fรถr varje paket, sortera i fallande ordning och ta det stรถrsta tillgรคngliga fรถrhรฅllandet fรถrst tills ryggsรคcken รคr full.

Fรถr det sanna Fraktionerad variant, nรคr nรคsta paket inte fรฅr plats helt, ta en brรฅkdel som exakt fyller den รฅterstรฅende kapaciteten. Den extra regeln รคr det som gรถr Greedy Three bevisligen optimal pรฅ Fractional Knapsack.

Greedy Three-paketval

Steg i algoritmen

Fรถr 0/1-varianten med gren och bundna punkter driver den sorterade enhetskostnadslistan ett sรถktrรคd:

  • Steg 1: Rotnoden representerar en tom ryggsรคck. TotalValue = 0. UpperBound = M ร— maximal enhetskostnad.
  • Steg 2: Fรถrgrena roten efter hur mรฅnga kopior av paketet med stรถrsta fรถrhรฅllandet som fรฅr plats. Fรถr varje barn, berรคkna om TotalValue, รฅterstรฅende kapacitet M och UpperBound.
  • Steg 3: Utรถka barnet med den stรถrsta รถvre grรคnsen fรถrst, i hopp om att snabbt hitta en stark lรถsning.
  • Steg 4: Beskรคr alla noder vars UpperBound inte รคr bรคttre รคn den nuvarande bรคsta kompletta lรถsningen.
  • Steg 5: Nรคr varje nod antingen utรถkas eller beskรคrs รคr den nuvarande bรคsta kompletta lรถsningen optimal.

Pseudokod fรถr den rena fraktionella ryggsรคcksgiriga algoritmen:

Fractional Knapsack (Array W, Array V, int M)
1. for i <- 1 to size(V)
2.     cost[i] <- V[i] / W[i]
3. Sort-Descending(cost)
4. total <- 0
5. i <- 1
6. while (i <= size(V) and M > 0)
7.     if W[i] <= M
8.         M <- M - W[i]
9.         total <- total + V[i]
10.        i <- i + 1
11.    else
12.        total <- total + V[i] * (M / W[i])
13.        M <- 0

Algoritmens komplexitet:

  • Med en enkel sortering (urval eller bubbla): O(n2).
  • Anvรคndning av snabb sortering eller sammanslagningssortering: O(n log n), dominerad av sorteringssteget.

Java Code fรถr giriga tre

Definiera KnapsackPackage klass med vikt, vรคrde och hรคrledd kostnad (V/W-fรถrhรฅllandet som anvรคnds fรถr sortering):

public class KnapsackPackage {

    private double weight;
    private double value;
    private Double cost;

    public KnapsackPackage(double weight, double value) {
        super();
        this.weight = weight;
        this.value = value;
        this.cost = Double.valueOf(value / weight);
    }

    public double getWeight() { return weight; }

    public double getValue() { return value; }

    public Double getCost()  { return cost; }
}

Skapa sedan funktionen som implementerar Greedy Three:

public void knapsackGreProc(int W[], int V[], int M, int n) {
    KnapsackPackage[] packs = new KnapsackPackage[n];
    for (int i = 0; i < n; i++) {
        packs[i] = new KnapsackPackage(W[i], V[i]);
    }

    Arrays.sort(packs, new Comparator<KnapsackPackage>() {
        @Override
        public int compare(KnapsackPackage a, KnapsackPackage b) {
            return b.getCost().compareTo(a.getCost());
        }
    });

    double remain = M;
    double result = 0d;

    for (int i = 0; i < n && remain > 0; i++) {
        if (packs[i].getWeight() <= remain) {
            remain -= packs[i].getWeight();
            result += packs[i].getValue();
            System.out.println("Pack " + i + " - Weight " + packs[i].getWeight()
                             + " - Value " + packs[i].getValue());
        } else {
            double fraction = remain / packs[i].getWeight();
            result += packs[i].getValue() * fraction;
            System.out.println("Pack " + i + " - Fraction " + fraction
                             + " - Value " + packs[i].getValue() * fraction);
            remain = 0;
        }
    }

    System.out.println("Max Value:\t" + result);
}

Funktion knapsackGreProc() in Java

Funktion knapsackGreProc() in Java

Fรถrklaring av kod:

  1. Slรฅ in varje inmatning i en KnapsackPackage sรฅ sorteringsnyckeln (V/W-fรถrhรฅllandet) รคr fรถrberรคknad.
  2. Sortera i fallande kostnadsordning.
  3. Ta varje paket hel om det fรฅr plats.
  4. Ta en brรฅkdel av nรคsta paket fรถr att fylla den รถverblivna kapaciteten.
  5. Stoppa sรฅ snart den รฅterstรฅende kapaciteten nรฅr noll.

ร…tgรคrdsanmรคrkning: ursprungliga Java loop avancerad i endast nรคr ett paket inte fick plats, vilket orsakade att samma paket togs upprepade gรฅnger. Versionen ovan flyttar fram ett paket per iteration och lรคgger till ett steg fรถr fraktionerad fyllning, vilket matchar den sanna regeln fรถr fraktionerad ryggsรคck.

Java drivrutin som kรถr algoritmen pรฅ ett fungerande exempel:

public void run() {
    int W[] = new int[]{15, 10, 2, 4};
    int V[] = new int[]{30, 25, 2, 6};
    int M = 37;
    int n = V.length;
    knapsackGreProc(W, V, M, n);
}

Python3 Code fรถr giriga tre

Definiera fรถrst KnapsackPackage klass. De __lt__ Metoden gรถr det direkt sorterbart efter kostnad:

class KnapsackPackage(object):
    """Knapsack Package Data Class"""

    def __init__(self, weight, value):
        self.weight = weight
        self.value  = value
        self.cost   = value / weight

    def __lt__(self, other):
        return self.cost < other.cost

Implementera sedan Fractional Knapsack-rutinen:

class FractionalKnapsack(object):

    def knapsackGreProc(self, W, V, M, n):
        packs = [KnapsackPackage(W[i], V[i]) for i in range(n)]
        packs.sort(reverse=True)

        remain = M
        result = 0

        for i in range(n):
            if remain == 0:
                break
            if packs[i].weight <= remain:
                remain -= packs[i].weight
                result += packs[i].value
                print("Pack", i, "- Weight", packs[i].weight, "- Value", packs[i].value)
            else:
                fraction = remain / packs[i].weight
                result += packs[i].value * fraction
                print("Pack", i, "- Fraction", fraction,
                      "- Value", packs[i].value * fraction)
                remain = 0

        print("Max Value:", result)

Funktion knapsackGreProc() in Python

Funktion knapsackGreProc() in Python

ร…tgรคrdsanmรคrkning: ursprungliga Python klassen definierade en tom __init__ utan kropp, som hรถjer IndentationErrorVersionen ovan tar bort den tomma konstruktorn eftersom ingen behรถvs.

Drivrutin som kรถr algoritmen i det fรถrsta exemplet:

if __name__ == "__main__":
    W = [15, 10, 2, 4]
    V = [30, 25, 2, 6]
    M = 37
    n = 4

    proc = FractionalKnapsack()
    proc.knapsackGreProc(W, V, M, n)

C# Code fรถr giriga tre

Definiera KnapsackPackage klass:

using System;

namespace KnapsackProblem
{
    public class KnapsackPackage
    {
        private double weight;
        private double value;
        private double cost;

        public KnapsackPackage(double weight, double value)
        {
            this.weight = weight;
            this.value  = value;
            this.cost   = value / weight;
        }

        public double Weight { get { return weight; } }
        public double Value  { get { return value; } }
        public double Cost   { get { return cost; } }
    }
}

Implementera Greedy Three med ett steg med fraktionerad fyllning:

public void KnapsackGreProc(int[] W, int[] V, int M, int n)
{
    KnapsackPackage[] packs = new KnapsackPackage[n];
    for (int k = 0; k < n; k++)
        packs[k] = new KnapsackPackage(W[k], V[k]);

    Array.Sort<KnapsackPackage>(packs,
        (a, b) => b.Cost.CompareTo(a.Cost));

    double remain = M;
    double result = 0d;

    for (int i = 0; i < n && remain > 0; i++)
    {
        if (packs[i].Weight <= remain)
        {
            remain -= packs[i].Weight;
            result += packs[i].Value;
            Console.WriteLine("Pack " + i + " - Weight " + packs[i].Weight
                            + " - Value " + packs[i].Value);
        }
        else
        {
            double fraction = remain / packs[i].Weight;
            result += packs[i].Value * fraction;
            Console.WriteLine("Pack " + i + " - Fraction " + fraction
                            + " - Value " + packs[i].Value * fraction);
            remain = 0;
        }
    }

    Console.WriteLine("Max Value:\t" + result);
}

Funktion KnapsackGreProc() i C#

Funktion KnapsackGreProc() i C#

Motexempel: Giriga tre pรฅ 0/1 ryggsรคck

Giriga Tre รคr optimal fรถr Brรฅkvarianten, men pรฅ 0/1 Ryggsรคcken (dรคr fรถremรฅl inte kan delas) kan den besegras. Motexempel:

  • Parametrar: n = 3, M = 10.
  • Paket: {i = 1; W = 7; V = 9; kostnad = 9/7}, {i = 2; W = 6; V = 6; kostnad = 1}, {i = 3; W = 4; V = 4; kostnad = 1}.
  • Greedy Three vรคljer paket 1 fรถr totalt vรคrde 9, medan det optimala 0/1-valet (paket 2, paket 3) nรฅr 10.

Lรคrdomen: anvรคnd Greedy Three endast nรคr brรฅk รคr tillรฅtna. Fรถr 0/1-varianten, anvรคnd Dynamisk programmering istรคllet.

Tillรคmpningar av fraktionerad ryggsรคck

  • Lastning dรคr flytande, pulveriserade eller bulkgods kan delas upp efter vikt.
  • Portfรถljallokering รถver investeringsalternativ som accepterar delfinansiering.
  • Molnbandbreddsdelning dรคr flรถden kan fรถrbruka en brรฅkdel av en lรคnk.
  • CPU-schemalรคggning under en delad tidssegmentmodell med delbara arbetsbelastningar.
  • AI-resursallokering dรคr ett utbildningsjobb kan anvรคnda en brรฅkdel av en GPU.

Vanliga frรฅgor

I brรฅkdelsryggsรคcksproblemet ska du fylla en ryggsรคck med kapacitet M med fรถremรฅl som kan delas. Varje fรถremรฅl har en vikt och ett vรคrde; mรฅlet รคr att maximera det totala vรคrdet samtidigt som kapaciteten respekteras.

Att sortera efter vรคrde-vikt-fรถrhรฅllande och ta det hรถgsta fรถrhรฅllandet fรถrst รคr bevisligen optimalt eftersom varje byte till ett objekt med lรคgre fรถrhรฅllande sรคnker det totala vรคrdet per kapacitetsenhet. Brรฅkdelar lรฅter det sista objektet exakt fylla รฅterstรฅende utrymme.

Med Fractional Knapsack kan du ta en bit av vilket fรถremรฅl som helst och lรถses med en girig vรคrde/vikt-sortering. 0/1 Ryggsรคck krรคver hela objekt och behรถver dynamisk programmering fรถr ett optimalt svar.

Sortering efter vรคrde-till-vikt-fรถrhรฅllande dominerar kรถrtiden. Med snabb sortering eller sammanslagningssortering kรถrs algoritmen i O(n log n). Urval eller bubbelsortering hรถjer den till O(n i kvadrat). Sjรคlva den giriga urvalsslingan รคr O(n).

Utan brรฅk kan det giriga valet lรคmna oanvรคnd kapacitet som ett smartare byte skulle fylla. Det klassiska fallet (W = 7, 6, 4; V = 9, 6, 4; M = 10) vรคljer vรคrdet 9 medan det optimala 0/1-svaret nรฅr 10.

Lastning av bulkvaror, portfรถljallokering, delning av molnbandbredd, schemalรคggning av CPU-tidsintervall och AI-resursallokering รถver delbara arbetsbelastningar. Alla situationer dรคr artiklar kan skivas efter vikt รคr en kandidat.

Agenter fรถr fรถrstรคrkningsinlรคrning packar molnuppgifter under GPU- eller minnesgrรคnser, och maskininlรคrningsmodeller fรถrutspรฅr bra branch-and-bound-ordningar. Pรฅ den fraktionella varianten fรถrblir girig optimal, sรฅ AI riktar sig huvudsakligen mot 0/1-fallet.

Ja. GitHub Copilot stรถder vรคrde/vikt-sorteringen, den giriga loopen och fraktionsfyllningssteget. Java, Python, eller C#, och genererar enhetstester som verifierar att algoritmen trรคffar det kรคnda optimala pรฅ klassiska indatamรคngder.

Sammanfatta detta inlรคgg med: