logo

Dynamisk programmering

Dynamisk programmering er en teknikk som bryter opp problemene i deloppgaver, og lagrer resultatet til fremtidige formål slik at vi ikke trenger å beregne resultatet på nytt. Delproblemene er optimalisert for å optimalisere den samlede løsningen er kjent som optimal underkonstruksjonsegenskap. Hovedbruken av dynamisk programmering er å løse optimaliseringsproblemer. Her betyr optimaliseringsproblemer at når vi prøver å finne ut minimums- eller maksimumsløsningen av et problem. Den dynamiske programmeringen garanterer å finne den optimale løsningen på et problem hvis løsningen eksisterer.

Definisjonen av dynamisk programmering sier at det er en teknikk for å løse et komplekst problem ved først å bryte inn i en samling av enklere delproblemer, løse hvert delproblem bare én gang, og deretter lagre løsningene deres for å unngå repeterende beregninger.

La oss forstå denne tilnærmingen gjennom et eksempel.

Tenk på et eksempel på Fibonacci-serien. Følgende serie er Fibonacci-serien:

kontroll strukturer python

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ,...

Tallene i serien ovenfor er ikke tilfeldig beregnet. Matematisk kan vi skrive hvert av begrepene ved å bruke formelen nedenfor:

F(n) = F(n-1) + F(n-2),

Med grunnverdiene F(0) = 0, og F(1) = 1. For å beregne de andre tallene følger vi forholdet ovenfor. For eksempel er F(2) summen f(0) og f(1), som er lik 1.

Hvordan kan vi beregne F(20)?

F(20)-leddet vil bli beregnet ved å bruke den n-te formelen i Fibonacci-serien. Figuren nedenfor viser hvordan F(20) beregnes.

if else-setning i java
Dynamisk programmering

Som vi kan observere i figuren ovenfor at F(20) beregnes som summen av F(19) og F(18). I den dynamiske programmeringstilnærmingen prøver vi å dele problemet inn i de lignende delproblemene. Vi følger denne tilnærmingen i tilfellet ovenfor hvor F(20) inn i de lignende underproblemene, dvs. F(19) og F(18). Hvis vi oppsummerer definisjonen av dynamisk programmering, sier den at det lignende underproblemet ikke skal beregnes mer enn én gang. Likevel, i tilfellet ovenfor, beregnes delproblemet to ganger. I eksemplet ovenfor beregnes F(18) to ganger; på samme måte beregnes F(17) også to ganger. Denne teknikken er imidlertid ganske nyttig ettersom den løser de lignende underproblemene, men vi må være forsiktige når vi lagrer resultatene fordi vi ikke er spesielt opptatt av å lagre resultatet som vi har beregnet en gang, da kan det føre til sløsing med ressurser.

I eksemplet ovenfor, hvis vi beregner F(18) i det høyre undertreet, fører det til en enorm ressursbruk og reduserer den totale ytelsen.

Løsningen på problemet ovenfor er å lagre de beregnede resultatene i en matrise. Først beregner vi F(16) og F(17) og lagrer verdiene deres i en matrise. F(18) beregnes ved å summere verdiene til F(17) og F(16), som allerede er lagret i en matrise. Den beregnede verdien til F(18) lagres i en matrise. Verdien av F(19) beregnes ved å bruke summen av F(18) og F(17), og verdiene deres er allerede lagret i en matrise. Den beregnede verdien til F(19) lagres i en matrise. Verdien til F(20) kan beregnes ved å legge til verdiene til F(19) og F(18), og verdiene til både F(19) og F(18) lagres i en matrise. Den endelige beregnede verdien av F(20) lagres i en matrise.

Hvordan fungerer tilnærmingen til dynamisk programmering?

Følgende er trinnene som den dynamiske programmeringen følger:

  • Det bryter ned det komplekse problemet i enklere delproblemer.
  • Den finner den optimale løsningen på disse delproblemene.
  • Den lagrer resultatene av delproblemer (memoisering). Prosessen med å lagre resultatene av delproblemer er kjent som memorering.
  • Den gjenbruker dem slik at samme delproblem beregnes mer enn én gang.
  • Beregn til slutt resultatet av det komplekse problemet.

De fem trinnene ovenfor er de grunnleggende trinnene for dynamisk programmering. Den dynamiske programmeringen er anvendelig som har egenskaper som:

hvordan bryte ut av en while loop java

De problemene som har overlappende underproblemer og optimale understrukturer. Her betyr optimal understruktur at løsningen av optimaliseringsproblemer kan oppnås ved ganske enkelt å kombinere den optimale løsningen av alle delproblemene.

Når det gjelder dynamisk programmering, vil romkompleksiteten øke når vi lagrer mellomresultatene, men tidskompleksiteten vil reduseres.

Tilnærminger til dynamisk programmering

Det er to tilnærminger til dynamisk programmering:

  • Top-down tilnærming
  • Bottom-up-tilnærming

Top-down tilnærming

Top-down-tilnærmingen følger memoreringsteknikken, mens bottom-up-tilnærmingen følger tabuleringsmetoden. Her er memorering lik summen av rekursjon og caching. Rekursjon betyr å kalle opp selve funksjonen, mens caching betyr å lagre mellomresultatene.

Fordeler

  • Det er veldig enkelt å forstå og implementere.
  • Det løser underproblemene bare når det er nødvendig.
  • Det er lett å feilsøke.

Ulemper

intelligent idé vs formørkelse

Den bruker rekursjonsteknikken som opptar mer minne i anropsstakken. Noen ganger når rekursjonen er for dyp, vil stabeloverløpstilstanden oppstå.

Den opptar mer minne som forringer den generelle ytelsen.

La oss forstå dynamisk programmering gjennom et eksempel.

 int fib(int n) { if(n<0) error; if(n="=0)" return 0; 1; sum="fib(n-1)" + fib(n-2); } < pre> <p>In the above code, we have used the recursive approach to find out the Fibonacci series. When the value of &apos;n&apos; increases, the function calls will also increase, and computations will also increase. In this case, the time complexity increases exponentially, and it becomes 2<sup>n</sup>.</p> <p>One solution to this problem is to use the dynamic programming approach. Rather than generating the recursive tree again and again, we can reuse the previously calculated value. If we use the dynamic programming approach, then the time complexity would be O(n).</p> <p>When we apply the dynamic programming approach in the implementation of the Fibonacci series, then the code would look like:</p> <pre> static int count = 0; int fib(int n) { if(memo[n]!= NULL) return memo[n]; count++; if(n<0) error; if(n="=0)" return 0; 1; sum="fib(n-1)" + fib(n-2); memo[n]="sum;" } < pre> <p>In the above code, we have used the memorization technique in which we store the results in an array to reuse the values. This is also known as a top-down approach in which we move from the top and break the problem into sub-problems.</p> <h3>Bottom-Up approach</h3> <p>The bottom-up approach is also one of the techniques which can be used to implement the dynamic programming. It uses the tabulation technique to implement the dynamic programming approach. It solves the same kind of problems but it removes the recursion. If we remove the recursion, there is no stack overflow issue and no overhead of the recursive functions. In this tabulation technique, we solve the problems and store the results in a matrix.</p> <p>There are two ways of applying dynamic programming:</p> <ul> <tr><td>Top-Down</td>  </tr><tr><td>Bottom-Up</td>  </tr></ul> <p>The bottom-up is the approach used to avoid the recursion, thus saving the memory space. The bottom-up is an algorithm that starts from the beginning, whereas the recursive algorithm starts from the end and works backward. In the bottom-up approach, we start from the base case to find the answer for the end. As we know, the base cases in the Fibonacci series are 0 and 1. Since the bottom approach starts from the base cases, so we will start from 0 and 1.</p> <p> <strong>Key points</strong> </p> <ul> <li>We solve all the smaller sub-problems that will be needed to solve the larger sub-problems then move to the larger problems using smaller sub-problems.</li> <li>We use for loop to iterate over the sub-problems.</li> <li>The bottom-up approach is also known as the tabulation or table filling method.</li> </ul> <p> <strong>Let&apos;s understand through an example.</strong> </p> <p>Suppose we have an array that has 0 and 1 values at a[0] and a[1] positions, respectively shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-2.webp" alt="Dynamic Programming"> <p>Since the bottom-up approach starts from the lower values, so the values at a[0] and a[1] are added to find the value of a[2] shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-3.webp" alt="Dynamic Programming"> <p>The value of a[3] will be calculated by adding a[1] and a[2], and it becomes 2 shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-4.webp" alt="Dynamic Programming"> <p>The value of a[4] will be calculated by adding a[2] and a[3], and it becomes 3 shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-5.webp" alt="Dynamic Programming"> <p>The value of a[5] will be calculated by adding the values of a[4] and a[3], and it becomes 5 shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-6.webp" alt="Dynamic Programming"> <p>The code for implementing the Fibonacci series using the bottom-up approach is given below:</p> <pre> int fib(int n) { int A[]; A[0] = 0, A[1] = 1; for( i=2; i<=n; i++) { a[i]="A[i-1]" + a[i-2] } return a[n]; < pre> <p>In the above code, base cases are 0 and 1 and then we have used for loop to find other values of Fibonacci series.</p> <p> <strong>Let&apos;s understand through the diagrammatic representation.</strong> </p> <p>Initially, the first two values, i.e., 0 and 1 can be represented as:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-7.webp" alt="Dynamic Programming"> <p>When i=2 then the values 0 and 1 are added shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-8.webp" alt="Dynamic Programming"> <p>When i=3 then the values 1and 1 are added shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-9.webp" alt="Dynamic Programming"> <p>When i=4 then the values 2 and 1 are added shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-10.webp" alt="Dynamic Programming"> <p>When i=5, then the values 3 and 2 are added shown as below:</p> <img src="//techcodeview.com/img/daa-tutorial/79/dynamic-programming-11.webp" alt="Dynamic Programming"> <p>In the above case, we are starting from the bottom and reaching to the top.</p> <hr></=n;></pre></0)></pre></0)>