Fundamentals of artificial intelligence - dynamic programming

Posted by cemzafer on Wed, 19 Jan 2022 23:34:19 +0100

Dynamic programming and operations research

In Tianji horse racing, inferior horses are used against superior horses, and superior and medium horses are used against medium and inferior horses. This is an application of operations research

Operations research is a branch of Applied Mathematics, which is used to solve decision-making problems and use mathematical methods to make the best arrangement. It also occupies an important position in game theory

Dynamic programming is a branch of operations research and a process of calculating the best decision. Its main idea is "decomposition" and "memory". Decomposition is to divide a problem into several similar subproblems; Memory, that is, save the calculated results to prevent repeated calculation

Applicable conditions

Optimality principle

If the decision of the current problem is the optimal decision, the decision of the subproblem must also be the optimal decision

No aftereffect principle

The decision of the sub problem cannot directly affect the decision of the parent problem. Whether the decision of the sub problem is the best decision or not will not affect the decision of the parent problem, but if the decision of the sub problem is not the best decision, the decision of the parent problem must not be the best decision

Overlapping principle

The parent problem can be decomposed into multiple sub problems, and the sub problems can also be decomposed into multiple sub problems. These sub problems may be repeated. In order to reduce the number of calculations, the solution of the sub problem needs to be saved after calculation and can be used directly next time

Fibonacci sequence

Problem description

Find the 50th term of the Fibonacci sequence in which the first two terms are 1

Problem decomposition

Use f(n) to represent the nth Fibonacci number, then f(n)=f(n-1)+f(n-2), and when n=1,2, f(n)=1

code implementation

#include <iostream>
#include <stdio.h>
#include <string.h>
 
long long fib[51]{};
 
long long Fibonacci(int i);
 
int main(){
    //Print the 50th Fibonacci number
    printf("%lld\n", Fibonacci(50));
    return 0;
}
 
//Returns the number of the ith Fibonacci sequence
long long Fibonacci(int i){
    if(fib[i] != 0) return fib[i];
    if(i <= 2){
        fib[i] = 1;
    } else{
        fib[i] = Fibonacci(i-1) + Fibonacci(i-2);
    }
    return fib[i];
}

Number tower problem

Problem description

Description There is a triangular number tower, the vertex node is the root node, and each node has an integer value. Starting from the vertex, you can choose to go down left or right at each node and go all the way to the bottom. It is required to find a path to maximize the sum on the path. Input Enter the number of tower floors n Enter the number of n floors Output Output maximum sum Sample Input 5 13 11 8 12 7 26 6 14 15 8 12 7 13 24 11 Sample Output max=86

Problem decomposition

Let the number of layers I and j be a[i][j], and the maximum sum of downward steps is f(i, j), then f(i, j)=a[i, j] + max{f(i+1,j),f(i+1,j+1)}

code implementation

#include <iostream>
#include <stdio.h>
#include <string.h>
 
using namespace std;
 
int n;
int **arr;//Because the range of n is unknown, it is defined in pointer mode
int **res;//Store calculated results
 
int f(int i, int j);
 
int main() {
    cin >> n;//Enter the number of layers
    arr = new int *[n];
    res = new int *[n];
    for(int i=0;i<n;i++){
        arr[i] = new int [n];
        res[i] = new int [n]{};//Initializes the array to 0 while defining the pointer
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<=i;j++){
            cin >> arr[i][j];//Enter number
        }
    }
    cout << "max=" << f(0,0);
    return 0;
}
 
int f(int i, int j){
    if(res[i][j] != 0) return res[i][j];
    if(i >= n-1){//Has reached the bottom
        res[i][j] = arr[i][j];
    }else{
        res[i][j] = arr[i][j] + max(f(i+1,j),f(i+1,j+1));;
    }
    return res[i][j];
}

Longest common subsequence

Problem description

Description Given two strings, the longest common subsequence length of the two strings is output Input Enter 2 strings (ensure that the string length does not exceed 500) Multiple groups of data in the file end with '#' Output Output longest common subsequence length Sample Input abc abc abcd acdef # Sample Output 3 3

Problem decomposition

Let function f(i,j) return the longest common sequence length starting from the ith character of string a and starting from the jth character of string b. When i==j, f(i,j)=f(i-1,j-1)+1, otherwise, f(i,j)=max{f(i,j-1),f(i-1,j)}

code implementation

#include <iostream>
#include <stdio.h>
#include <string.h>
 
using namespace std;
 
char a[501];//Sequence A
char b[501];//Sequence B
int len_a,len_b;
int res[501][501];
 
int f(int i, int j);
 
int main() {
    while (cin >> a && a[0] != '#' && cin >> b) {
        //Initialize res array
        for (int i = 0; i < 501; i++) {
            for (int j = 0; j < 501; j++) {
                res[i][j] = -1;
            }
        }
        len_a = strlen(a);
        len_b = strlen(b);
        cout << f(0,0) << endl;
    }
    return 0;
}
 
int f(int i, int j) {
    if(i >= len_a || j >= len_b) return 0;
    if (res[i][j] != -1) return res[i][j];
    if (a[i] == b[j]) {
        res[i][j] = f(i + 1, j + 1) + 1;
    } else {
        res[i][j] = max(f(i + 1, j), f(i, j + 1));
    }
    return res[i][j];
}

01 Backpack

See details 01 knapsack problem backtracking and dynamic programming solution

Missile interception

Problem description

Description In order to defend against the missile attack of the enemy, a certain country has developed a missile interception system. However, this missile interception system has a defect: although its first shell can reach any height, each shell in the future cannot be higher than the height of the previous one. One day, the radar caught the enemy's missile attack. Since the system is still in the trial stage, there is only one system, so it may not be able to intercept all missiles. Input the altitude of the missiles in turn (the altitude data given by the radar is a positive integer not greater than 30000), and calculate the maximum number of missiles that the system can intercept, and the minimum number of such missile interception systems if all missiles are to be intercepted. Input Input multiple data M: (m < = 30000) 389 207 155 300 299 170 158 65 Output 6 (maximum number of missiles that can be intercepted) 2 (minimum number of systems to intercept all missiles) Sample Input 389 207 155 300 299 170 158 65 Sample Output 6 2

Problem decomposition

Interceptors are getting lower and lower every time, which means that the height of missiles will be lower and lower every time. If the intercepted missiles are sorted by serial number, their height will be a descent sequence, so the maximum number of missiles that can be intercepted is the length of the longest descent subsequence

Similarly, each time the longest descending subsequence is calculated, remove this subsequence and repeat the calculation, so the minimum number of systems equipped is the number of descending subsequences. Obviously, the number of descending subsequences is the length of the longest ascending subsequence, because in the ascending subsequence, each item must be distributed in different descending sequences

Let the number of missiles be len, f(i) represents the length of the longest descent subsequence starting from i. only find the missile j from the missile behind it, so that height (i) > = height (J), and f(j)+1 > = f(i), then the value of f(i) is f(j)+1

g(i) represents the length of the longest ascending subsequence starting from i. It is the same as f(i), but the condition should be changed to height (i) < height (J)

code implementation

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include <string>
 
using namespace std;
 
int temp;
int height[1000];
int len = 0;
 
int res_f[1000]{};
int res_g[1000]{};
 
int f(int i);//Longest descent subsequence
int g(int i);//Longest ascending subsequence
 
int max_f = 1, max_g = 1;//Record maximum
 
int main() {
    string s;
    getline(cin, s);
    istringstream istr(s);
    //Read Missile Altitude
    while (istr >> temp) {
        height[len] = temp;
        len++;
    }
    //Find the maximum value
    for (int i = 0; i < len; i++) {
        if (f(i) > max_f) max_f = f(i);
        if (g(i) > max_g) max_g = g(i);
    }
    cout << max_f << endl << max_g << endl;
    return 0;
}
 
int f(int i) {
    if (res_f[i] != 0) return res_f[i];
    res_f[i] = 1;//Because it is itself a sequence, the initial value is 1 and the minimum value is 1
    if (i < len - 1) {
        for (int j = i + 1; j < len; j++) {
            if (height[i] >= height[j] && f(j) + 1 >= res_f[i]) res_f[i] = f(j) + 1;
        }
    }
    return res_f[i];
}
 
int g(int i) {
    if (res_g[i] != 0) return res_g[i];
    res_g[i] = 1;//Because it is itself a sequence, the initial value is 1 and the minimum value is 1
    if (i < len - 1) {
        for (int j = i + 1; j < len; j++) {
            if (height[i] < height[j] && g(j) + 1 >= res_g[i]) res_g[i] = g(j) + 1;
        }
    }
    return res_g[i];
}