動態規劃

常聽到的DP(Dynamic Programming)

大問題

小問題

小問題

小問題

小問題

定義

大問題

小問題

小問題

小問題

小問題

大問題

小問題

小問題

小問題

小問題

大問題

小問題

小問題

小問題

小問題

大問題

小問題

小問題

小問題

小問題

大問題

小問題

小問題

小問題

小問題

大問題

小問題

小問題

小問題

小問題

大問題

小問題

for(int i=0;i<4;i++)

大問題

小問題

for(int i=0;i<4;i++)

太過耗時

大問題

小問題

for(int i=0;i<4;i++)

太過耗時

大問題

小問題的解no.1

小問題的解no.2

小問題的解no.3

小問題的解no.4

a[4]

example

費氏數列:

每次輸入皆為一整數n,且n不大於50,可無限輸入

請輸出費氏數列第n項的值

example

遞迴解法:

#include <bits/stdc++.h>

using namespace std;

int f(int n){
    if(n==1) return 1;
    else if(n==2) return 1;
    else{
        return f(n-2)+f(n-1);
    }
}
int main(){
    int n;
    while(cin>>n){
        cout<<f(n)<<endl;
    }
    
    return 0;
}

example

DP想法:

if n==10,f(n)=?

f[11]

. . .

n=1

n=2

n=3

n=4

n=10

1

1

2

3

55

f[1]+f[2]

f[2]+f[3]

f[8]+f[9]

example

DP解法:

#include <bits/stdc++.h>

using namespace std;

int main(){

    ios::sync_with_stdio(0);
    cin.tie(0);
    int f[51],n;
    f[1]=1;
    f[2]=1;
    for(int i=3;i<=50;i++){
        f[i]=f[i-1]+f[i-2];
    }
    while(cin>>n){
        cout<<f[n]<<endl;
    }
    return 0;
}

實作練習!

解題思路:

1:

2:

3:

4:

方法1種

方法2種

方法1+2種

solve

#include <bits/stdc++.h>

using namespace std;

int main(){
    long long int n,wall[51]={0,1,2};
    for(int i=3;i<51;i++){
        wall[i]=wall[i-1]+wall[i-2];
    }
    while(cin>>n){
        if(n==0) break;
        cout<<wall[n]<<endl;
    }
    return 0;
}

解題思路:if只走邊

0  7  8 9

1   5  1  1

2  4 10 0

解題思路:if只走邊

0  7  15 9

1   5  1  1

3  4 10 0

解題思路:if只走邊

0  7  15 24

1   5  1  1

3  4 10 0

解題思路:if走裡面

7  15 24

1   5  1  1

3  4 10 0

1<7

解題思路:if走裡面

7  15 24

1   6  1  1

3  4 10 0

1<7

解題思路:if走裡面

7  15 24

1   6 1  1

3  4 10 0

6<15

解題思路:if走裡面

7  15 24

1   6  7  1

3  4 10 0

6<15

解題思路:if走裡面

7  15 24

1   6  7  1

3  4 10 0

7<24

解題思路:if走裡面

7  15 24

1   6  7  8

3  4 10 0

7<24

解題思路:if走裡面

7  15 24

1   6  7  8

3  4 10 0

8<10

解題思路:if走裡面

7  15 24

1   6  7  8

3  4 10 8

8<10

解題思路:if走裡面

7  15 24

1   6  7  8

3  4 10 8

8<10

解題思路:why not從上跟下選比較小的走呢?

7  8 9

1   5  1  1

2  4 10 0

解題思路:why not從上跟左選比較小的走呢?

7  8 9

1   5  1  1

2  4 10 0

解題思路:why not從上跟下選比較小的走呢?

7  8 9

1   5  1  1

2  4 10 0

解題思路:why not從上跟下選比較小的走呢?

7  8 9

1   5  1  1

2  4 10 0

解題思路:why not從上跟下選比較小的走呢?

7  8 9

1   5  1  1

3  4 10 0

解題思路:why not從上跟下選比較小的走呢?

7  8 9

1   5  1  1

3  7 17 17

解題思路:why not從上跟下選比較小的走呢?

7  8 9

1   5  1  1

3  7 17 17

解題思路:why not從上跟下選比較小的走呢?

7  8 9

1   5  1  1

3  7 17 17

解題思路:if走外面(上)

int sumM=0;
for(int i=1;i<m;i++){
    sumM+=map[0][i];
    map[0][i]=sumM;
}

解題思路:if走外面(左)

int sumN=0;
for(int i=1;i<n;i++){
    sumN+=map[i][0];
    map[i][0]=sumN;
}

解題思路:if走裡面

for(int i=1;i<n;i++){
    for(int j=1;j<m;j++){
        if(map[i-1][j]>map[i][j-1]){
            map[i][j]+=map[i][j-1];
        }
        else{
            map[i][j]+=map[i-1][j];
        }
    }
}

解題思路:我們先把它的重量以及承載量全除以10,我比較好做講解

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 0 0 0 0 0 0 0 0 0

w=3 v=60

前情提要:我們先把它的重量以及承載量全除以10,我比較好做講解

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 0 60 60 60 60 60 60 60 60

w=3 v=60

解題思路:我們先把它的重量以及承載量全除以10,我比較好做講解

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 50 60 60 110 110 110 110 110 110

w=2 v=50

解題思路:我們先把它的重量以及承載量全除以10,我比較好做講解

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 50 60 60 110 110 110 110 150 150

w=4 v=40

解題思路:我們先把它的重量以及承載量全除以10,我比較好做講解

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 50 60 60 110 110 110 110 150 150

w=6 v=70

解題思路:我們先把它的重量以及承載量全除以10,我比較好做講解

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 50 60 60 110 110 110 110 150 150

biggest is 150

解題思路:如何解決

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 0 0 0 0 0 0 0 0 0

w=3 v=60

箭頭範圍代表可以將重量為3之物體放入

故將陣列之值設為其所代表之重量

解題思路:如何解決

w=3 v=60

箭頭範圍代表可以將重量為3之物體放入

故將陣列之值設為其所代表之價值

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 0 60 60 60 60 60 60 60 60

w=2 v=50

解題思路:如何解決

w=3 v=60

箭頭範圍代表可以將重量為2之物體放入

例如k[5]為同時可放入兩者的空間數

則k[5]=k[5-2]+k[2]

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 0 60 60 60 60 60 60 60 60

w=2 v=50

解題思路:如何解決

箭頭範圍代表可以將重量為2之物體放入

例如k[5]為同時可放入兩者的空間數

則k[5]=k[5-2]+k[2]

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 50 60 60 110 60 60 60 60 60

w=2 v=50

若相比之下無較大則不變

解題思路:如何解決

箭頭範圍代表可以將重量為2之物體放入

例如k[5]為同時可放入兩者的空間數

則k[5]=k[5-2]+k[2]

k[1] k[2] k[3] k[4] k[5] k[6] k[7] k[8] k[9] k[10]
0 50 60 60 110 110 110 110 110 110

w=2 v=50

若兩者相加之值並無較大則不改變

解題思路:如何解決

for(int i=0;i<n;i++){
    for(int j=10;j>=w[i];j--){
        if(k[j-w[i]]+v[i]>k[j]){
           k[j]=k[j-w[i]]+v[i];
        }
    }
}

DP

By problemsolvemaster_kaitochiang