Notes on University Course "algorithm analysis and design"

Posted by faza on Tue, 14 Dec 2021 07:39:52 +0100

Junior algorithm design and analysis note summary and knowledge points sorting

Notes summary

Chapter 1 Introduction to Algorithms

1.1 algorithm and program

Algorithm definition: the method or process of solving a problem

Properties of the algorithm:

(1) Input: there are zero or more external quantities as the input of the algorithm

(2) Output: the algorithm generates at least one quantity as output

(3) Certainty: each instruction constituting the algorithm is clear and unambiguous

(4) Finiteness: the execution times of each instruction in the algorithm are limited, and the execution time of each instruction is also limited

Sometimes commonality or feasibility is added

Definition of program: it is the specific implementation of the algorithm in a programming language.

The difference between program and algorithm: the program can not meet the fourth property of the algorithm, that is, finiteness. An operating system, for example, is a program that executes in an infinite loop.

1.2 abstract mechanism of expression algorithm

In order to separate the top-level algorithm from the bottom-level algorithm, so that they do not restrict and influence each other in design, the interface between them must be abstracted. Let the bottom layer serve the top layer only through the interface, and the top layer calls the bottom operation only through the interface. This interface is the abstract data type (ADT).

1.3 description algorithm

There are many ways, such as natural language, table, high-level program language, etc

1.4 algorithm complexity analysis

The purpose of algorithm analysis: analyze the computer resources occupied by the algorithm, compare and evaluate the algorithm, and design a better algorithm

The complexity of the algorithm is the amount of computer resources required for the operation of the algorithm. The amount of time resources is called time complexity, and the amount of space resources is called space complexity.

C=F(N,I,A). N, I and A are used to represent the scale of the problem to be solved by the algorithm, the input of the algorithm and the algorithm itself, F is the determined ternary function of N, I and A, and C is the complexity

Generally, only three cases of time complexity are considered, namely, the worst case, the best case and the average case

Practice shows that the best operability and the most practical value is the time complexity in the worst case.

Complexity progressive behavior:

EXCEL
 about T(N),If present~T(N),Make it right N→∞happen now and then(T(N)-~T(N))/T(N)→0,Then say~T(N)yes T(N)When N→∞Asymptotic behavior of.

If there is a positive constant C and a natural number N0 such that f(N) ≤ Cg(N) when n ≥ N0, the function f(N) is said to be bounded when n is sufficiently large, and g(N) is an upper bound, which is recorded as f(N)=O(g(N)). At this time, it is also said that the order of f(N) is not higher than that of g(N).

For symbol O, there are the following operation rules:

O(f)+O(g)=O(max(f,g))

O(f)+O(g)=O(f+g)

O(f)O(g)=O(fg)

If g(N)=O(f(N)), then O(f)+O(g)=O(f)

O(Cf(N))=O(f(N)), where C is a positive constant

f=O(f)

Chapter 2 recursion and divide and conquer strategy

2.1 concept of recursion

The algorithm that directly or indirectly calls itself is called recursive algorithm. A function defined by the function itself is called a recursive function

Two elements of recursive function: boundary condition and recursive equation

Factorial function:

C++
#include<iostream>
using namespace std;

int factorial(int n){
    if(n==0) return 1;
    else{
        return n*factorial(n-1);
    }
}

Fibonacci sequence:

C++
#include<iostream>
using namespace std;

int fibonacci(int n){
    if(n<=1) return 1;
    else return fibonacci(n-1)+fibonacci(n-2);
} 

hanoi Tower:

PYTHON
def hanoi(n,a,b,c):
    #Move the n discs on a through c to b
    if(n>0):
        hanoi(n-1,a,c,b)
        move(a,b)
        hanoi(n-1,c,b,a)

Advantages of recursive algorithm: clear structure, strong readability, easy to prove the correctness of the algorithm by mathematical induction

The disadvantage of recursive algorithm: low efficiency, which consumes more computing time and storage space than non recursive algorithm

Methods to eliminate recursion: ① use a user-defined stack to simulate the recursive call work stack of the system, so as to change the recursive algorithm into a non recursive algorithm; ② use recursion to realize the recursive function

2.2 basic idea of divide and conquer

The basic idea of divide and conquer method: decompose a problem with scale n into k smaller subproblems, which are independent of each other and the same as the original problem. These subproblems are solved recursively, and then the solutions of each subproblem are combined to obtain the solution of the original problem.

Applicable conditions of divide and conquer method:

① The scale of the problem is reduced to a certain extent, which is easy to solve.

② The problem can be decomposed into several smaller same problems. That is, the problem has the property of optimal substructure.

③ The solutions of the subproblems decomposed by the problem can be combined into the solutions of the problem.

④ There are no common subproblems among subproblems (each subproblem is independent of each other)

Steps of divide and Conquer:

divide

solve

merge

2.3 binary search technology

PYTHON
def binarySearch(a,x):
    #a is the array and x is the number to search
    a=sorted(a)
    #a. order is required (from small to large)
    n=len(a)
    left,right=0,n-1
    while(left<=right):
        middle=(left+right)//2
        if(x==a[middle]):
            return middle
        elif(x>a[middle]):
            left=middle+1
        else:
            right=middle-1
    #not found
    return -1

In the worst case, the time complexity is O(logn)

2.4 large integer multiplication

Let X and y be n-bit binary integers, and now calculate their product xy. If you multiply directly, you need O(n^2) step, and the divide and conquer method is: divide the n-bit binary integers x and Y into 2 segments, and the length of each segment is n/2 bits:

MATHEMATICA
X=[A][B],Y=[C][D],among X,Y have n Bit; A,B,C,D All n/2 position
 From this, we can get:
X=A*2^(n/2)+B , Y=C*2^(n/2)+D

XY=(A*2^(n/2)+B)(C*2^(n/2)+D)
  =A*C*2^n+(A*D+C*B)*2^(n/2)+B*D
  =A*C*2^n+((A-B)(D-C)+A*C+B*D)*2^(n/2)+B*D

The last formula seems complicated, but it only needs to do 3 times of n/2-bit integer multiplication, 6 times of addition and subtraction and 2 times of shift

2.5 Strassen matrix multiplication

For square matrices (n*n) A,B,C, C=A*B, they are divided into four submatrixes of equal size, and each submatrix is a square matrix of (n/2)*(n/2)

2.7 merge sort

PYTHON
def merge(arr,left,mid,right):
    #left and right are the array ranges to be merged
    #mid is the middle subscript. The left is smaller than the median and the right is larger than the median
    i=left
    j=mid+1
    #Copy a temporary array
    aux=arr[:]
    for k in range(left,right+1):
        #If the left pointer exceeds mid, there is still left on the right
        if(i>mid):
            arr[k]=aux[j]
            j=j+1
        #If the right pointer exceeds right, there is left
        elif(j>right):
            arr[k]=aux[i]
            i=i+1
        #If the left is small, the left is merged
        elif(aux[i]<aux[j]):
            arr[k]=aux[i]
            i=i+1
        #If the right side is small
        else:
            arr[k]=aux[j]
            j=j+1


def mergeSort(arr,left,right):
    #If it has been traversed
    if(left>=right):
        return ;
    #Take the median value and disassemble it into left and right sides
    mid=(left+right)//2
    #Merge and sort the left half
    mergeSort(arr,left,mid)
    #Merge and sort the right half
    mergeSort(arr,mid+1,right)
    #Merge algorithm
    merge(arr,left,mid,right)

The worst-case time complexity is O(nlogn)

2.8 quick sort

Steps: decomposition, recursive solution, merging

PYTHON
def quicksort(arr,low,high):
    if low<high :
        index=getindex(arr,low,high)
        quicksort(arr,low,index-1)
        quicksort(arr,index+1,high)

#Core of quick sorting algorithm
#Function: place the number less than the reference value on the left and the number greater than the reference value on the right
def getindex(arr,low,high):
    #The first number is the standard value by default
    temp=arr[low]
    #When the traversal is not completed, the left and right pointers do not meet
    while(low<high):
        #If the right is greater than the standard value, the right pointer moves left
        while((low<high)and(arr[high]>=temp)):
            high=high-1
        #At this time, the corresponding value of the right pointer is less than the standard value, and it is copied to the left pointer position
        arr[low]=arr[high]
        #When the left is less than the standard value, the left pointer moves to the right
        while((low<high)and(arr[low]<=temp)):
            low=low+1
        #At this time, the left pointer copies the corresponding value greater than the standard value to the right pointer position
        arr[high]=arr[low]
    #Assign the standard value to the position where the left and right pointers meet
    arr[low]=temp
    #At this time, all low left sides are less than or equal to arr[low], and all low right sides are greater than or equal to arr[low]
    return low

The average time complexity of fast scheduling is O(nlogn), and the worst time complexity is O(n^2)

2.9 linear time selection

Find the number with the largest (smallest) X in a group

Random partition algorithm is adopted

2.10 nearest point pair problem

Time complexity analysis O(nlogn)

PYTHON
"""
Copyright: Copyright (c) 2019
Author: Justlovesmile
Title: Nearest point pair problem
"""

#Points sorted by x coordinate
class Point1:
    #x. Y is the coordinate and id is the serial number
    def __init__(self,xx,yy,index):
        self.x=xx
        self.y=yy
        self.id=index


#Points sorted by y coordinate
class Point2(Point1):
    #x. y is the coordinate, and id is the sequence number when the point is sorted by X
    def __init__(self,xx,yy,index):
        self.x=xx
        self.y=yy
        self.id=index
        
#Represents the plane point pair of the output
class Pair:
    #a. b is the point and dist is the distance
    def __init__(self, aa, bb,dd):
        self.a=aa
        self.b=bb
        self.dist=dd
    
#Find the distance between any two points u and V on the plane
def dist(u,v):
    dx=u.x-v.x
    dy=u.y-v.y
    return dx*dx+dy*dy

#Merge sort
def merge(S,order,left,mid,right):
    i=left
    j=mid+1
    aux=S[:]
    #Sort by x
    if(order=='x'):
        for k in range(left,right+1):
            if(i>mid):
                S[k]=aux[j]
                j=j+1
            elif(j>right):
                S[k]=aux[i]
                i=i+1
            elif(S[i].x<aux[j].x):
                S[k]=aux[i]
                i=i+1
            else:
                S[k]=aux[j]
                j=j+1
    #Sort by y
    elif(order=='y'):
        for k in range(left,right+1):
            if(i>mid):
                S[k]=aux[j]
                j=j+1
            elif(j>right):
                S[k]=aux[i]
                i=i+1
            elif(S[i].y<aux[j].y):
                S[k]=aux[i]
                i=i+1
            else:
                S[k]=aux[j]
                j=j+1

#Merge sort
def mergeSort(S,x,left,right):
    if(left>=right):
        return ;
    mid=(left+right)//2
    mergeSort(S,x,left,mid)
    mergeSort(S,x,mid+1,right)
    merge(S,x,left,mid,right)

#Calculate the closest point pair
def closePair(S,Y,Z,l,r):
    #Two points
    if(r-l==1):
        return Pair(S[l],S[r],dist(S[l],S[r]))
    #Three points
    if(r-l==2):
        d1=dist(S[l],S[l+1])
        d2=dist(S[l+1],S[r])
        d3=dist(S[l],S[r])
        if((d1<=d2)and(d1<=d3)):
            return Pair(S[l],S[l+1],d1)
        if(d2<=d3):
            return Pair(S[l+1],S[r],d2)
        else:
            return Pair(S[l],S[r],d3)
    #More than three points
    m=(l+r)//2
    f=l
    g=m+1
    for i in range(l,r+1):
        if(Y[i].id>m):
            Z[g]=Y[i] 
            g=g+1
        else:
            Z[f]=Y[i]
            f=f+1
    #Recursive solution
    best = closePair(S,Z,Y,l,m)
    right = closePair(S,Z,Y,m+1,r)
    #Select the nearest point pair
    if(right.dist<best.dist):
        best=right
    merge(Y,"y",l,m,r)

    k=l
    #Closest to the centerline
    for i in range(l,r+1):
        if(abs(S[m].x-Y[i].x)<best.dist):
            Z[k]=Y[i]
            k=k+1
    for i in range(l,k):
        for j in range(i+1,k):
            if(Z[j].y-Z[i].y<best.dist):
                dp=dist(Z[i],Z[j])
                if(dp<best.dist):
                    best=Pair(S[Z[i].id],S[Z[j].id],dp)
    #Return nearest point pair
    return best


#One dimensional point set
def cpair1(S):
    #Let it be positive infinity first
    min_d=float("inf")
    S=sorted(S)
    for i in range(1,len(S)):
        dist=abs(S[i]-S[i-1])
        if(dist<min_d):
            pair=[]
            min_d=dist
            pair.append([S[i-1],S[i]])
        elif(dist==min_d):
            pair.append([S[i-1],S[i]])
    print("Closest point:")
    for i in pair:
        print(i,end=" ")
    print("\nMin_dist:",min_d)

#2D point set
def cpair2(S):
    Y=[]
    n=len(S)
    if(n<2):
        return ;
    #Sort by X coordinate
    mergeSort(S,"x",0,n-1)
    #Assignment of Point2 type
    for i in range(n):
        p=Point2(S[i].x,S[i].y,i)
        Y.append(p)
    #Sort by y coordinate
    mergeSort(Y,"y",0,n-1)
    Z=Y[:]
    return closePair(S,Y,Z,0,n-1)
    
    
def main():
    #Enter a one-dimensional or two-dimensional point plane
    model=input("Please choose model of '1' or '2':").split()[0]
    S=[]
    #One dimensional point pair
    if(model == '1'):
        point=input("Please input a group of number in order:\n").split()
        #If you enter a null point pair
        if(len(point)==0):
            raise ValueError("You have entered a null point pair!")
        #Conversion type
        for i in range(len(point)):
            S.append(int(point[i]))
        #Output nearest point pair
        cpair1(S)
    #Two dimensional point pair
    elif(model == '2'):
        #Input points
        n=int(input("Please input how many points:\n"))
        if(n==0):
            raise ValueError("You have entered 0 points!")
        for i in range(n):
            words=f"please input the No.{i+1} point (like: x y) in x order:"
            point=input(words).split()
            p=Point1(int(point[0]),int(point[1]),i)
            S.append(p)
        #Find the nearest pair of points
        best=cpair2(S)
        print(f"The closest points are ({best.a.x},{best.a.y}) and ({best.b.x},{best.b.y}).")
        print(f"And the distance is {best.dist**0.5}.")
    else:
        raise ValueError("This option is not available!")

if __name__ == "__main__":
    #exception handling
    try:
        main()
    except Exception as e:
        print("Your input is illegal! The error message is as follows:")
        print(e)

Chapter III dynamic programming

The dynamic programming algorithm is similar to the divide and conquer method. Its basic idea is to decompose the problem to be solved into several sub problems. First solve the sub problems, and then get the solution of the original problem from the solutions of these sub problems. However, different from the divide and conquer method, the sub problems suitable for the problems solved by the dynamic programming method are often not independent of each other.

Steps of dynamic programming algorithm:

① Find out the properties of the optimal solution and characterize its structural characteristics

② Define the optimal value recursively

③ The optimal value is calculated in a bottom-up manner

④ According to the information obtained when calculating the optimal value, the optimal solution is constructed

Two basic elements of dynamic programming algorithm: optimal substructure and overlapping subproblem

Optimal substructure properties: the optimal solution of the problem includes the optimal solution of the subproblem

Overlapping subproblems: when the recursive algorithm is used to solve the problem from top to bottom, the subproblems generated each time are not always new problems, and some subproblems are calculated repeatedly

No aftereffect: after a problem is divided into stages, the state in stage I can only be obtained from the state in I+1 through the state transition equation, which has nothing to do with other states, especially with the state that has not occurred

The dynamic programming algorithm has a deformation method memo method, which is different from the filling direction of the dynamic programming algorithm "bottom-up", but the recursive direction of "top-down". A record item (memo) is established for each solved subproblem for review when necessary, and the repeated solution of the same subproblem can also be avoided

3.1 matrix multiplication problem

m(i,j) refers to the minimum number of times from A[i] to A[j] (1 ≤ I ≤ j ≤ n)

Matrix multiplicative condition: the number of columns of A is equal to the number of rows of B if A is A p × q matrix, B is A q × r matrix, then AB needs pqr times in total.

PYTHON
"""
Copyright: Copyright (c) 2019
Author: Justlovesmile
Title: Matrix multiplication problem
"""

#Calculate the optimal value
def matrixChain(p,m,s):
    #m[i][j] represents the minimum number of times required for A[i] to A[j]
    #s[i][j] represents the separation position corresponding to the minimum multiplication required by A[i] to A[j]
    n=len(p)-1
    for r in range(2,n+1):
        for i in range(1,n-r+2):
            #Advance in the direction of the slash
            j=r+i-1
            m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j]
            s[i][j]=i
            k=i+1
            #Find the optimal separation k between i and j
            while(k<j):
                t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]
                if(t<m[i][j]):
                    m[i][j]=t
                    s[i][j]=k
                k=k+1

#Recursive output according to S
def traceback(s,i,j):
    if(i==j):
        print(f"A[{i}]",end="")
        return ;
    print("(",end="")
    traceback(s,i,s[i][j])
    traceback(s,s[i][j]+1,j)
    print(")",end="")



def main():
    p=[]
    y=0
    #Number of input matrices
    n=input("Please iuput the number of matrix:").split()
    #exception handling
    if(len(n)==0):
        raise ValueError("You have entered an empty matrix!")
    n=int(n[0])
    #Enter information for each matrix
    for i in range(n):
        s=input(f"Input No.{i+1} Matrix size,eg:5 5\n").split()
        #Determine whether it can be multiplied by the previous item
        if(len(p)>=1):
            if(y!=int(s[0])):
                raise ValueError("The matrix you entered cannot be multiplied!")
        x,y=int(s[0]),int(s[1])
        p.append(x)
    p.append(y)
    m=[]
    s=[]
    for i in range(n+1):
        m.append([0]*(n+1))
        s.append([0]*(n+1))
    matrixChain(p,m,s)  
    traceback(s,1,n)
    print("\nCount times:",m[1][n])
    

    

if __name__ =="__main__":
    #exception handling
    try:
        main()
    except Exception as e:
        print("Your input is illegal! The error message is as follows:")
        print(e)

3.3 longest common subsequence

Establish recursive relationship:

PYTHON
"""
Copyright: Copyright (c) 2019
Author: Justlovesmile
Title: Longest common subsequence problem
"""

def IcsLength(x,y,b):
    m=len(x)
    n=len(y)
    #initialization
    c=[]
    for j in range(m+1):
        c.append([0]*(n+1))
    #Compare one by one
    for i in range(1,m+1):
        for j in range(1,n+1):
            #If equal, the longest common length at this time is the longest common length + 1 after removing the position
            if(x[i-1]==y[j-1]):
                c[i][j]=c[i-1][j-1]+1
                #The value of record c[i][j] is obtained from the solution of the first kind of subproblem
                b[i][j]=1
            #If the corresponding positions are not equal, compare the longest subsequence of which side of the two sequences will be longer after removing the inequality
            elif(c[i-1][j]>=c[i][j-1]):
                c[i][j]=c[i-1][j]
                b[i][j]=2
            else:
                c[i][j]=c[i][j-1]
                b[i][j]=3
    return c[m][n]

#Output the longest subsequence according to b[i][j]
def Ics(i,j,x,b):
    if(i==0 or j==0):
        return ;
    #If it is the solution of the first kind of subproblem, it means that the location is a common part
    if(b[i][j]==1):
        Ics(i-1,j-1,x,b)
        print(x[i-1],end="")
    #If it is the solution of the second kind of subproblem, it means that Zk ≠ Xm at this time
    elif(b[i][j]==2):
        Ics(i-1,j,x,b)
    #Zk≠Yn
    else:
        Ics(i,j-1,x,b)

def main():
    #Input string
    A=input("Please input No.1 Ics:").split()
    B=input("Please input No.2 Ics:").split()
    b=[]
    for i in range(len(A)+1):
        b.append([0]*(len(B)+1))
    print("The longest length:",IcsLength(A,B,b))
    Ics(len(A),len(B),A,b)

if __name__=="__main__":
    #exception handling
    try:
        main()
    except Exception as e:
        print("Your input will not be legal! The error message is as follows:")
        print(e)

3.4 optimal triangulation of convex polygon

Similar to matrix multiplication

PYTHON
"""
Copyright: Copyright (c) 2019
Author: Justlovesmile
Title: Optimal triangulation of convex polygon
"""
from isConvex import isConvex

#Calculate the optimal value
def minWeightTriangulation(n,t,s,v):
    #t[i][j] is a convex sub polygon vi-1, VI, The value of weight function corresponding to the optimal triangulation of VJ
    for r in range(2,n+1):
        for i in range(1,n-r+2):
            j=r+i-1
            t[i][j]=t[i+1][j]+weight(i-1,i,j,v)
            s[i][j]=i
            k=i+1
            #Traverse all edges from i to j
            while(k<j):
                u=t[i][k]+t[k+1][j]+weight(i-1,k,j,v)
                if(u<t[i][j]):
                    t[i][j]=u
                    s[i][j]=k
                k=k+1

#Divide the results according to s output
def traceback(s,i,j):
    if(i==j):
        print(f"B[{i}]",end="")
        return ;
    print("(",end="")
    traceback(s,i,s[i][j])
    traceback(s,s[i][j]+1,j)
    print(")",end="")

#Calculate weights based on distance
def weight(i,j,k,v):
    return dist(i,j,v)+dist(i,k,v)+dist(k,j,v)

#Calculate distance
def dist(i,j,v):
    return (v[i][0]-v[j][0])**2+(v[i][1]-v[j][1])**2

def main():
    v=[]
    #You can choose to enter manually and use default values
    ans=input("Do you want to use default v[]:(y / n )")
    if(ans=="y" or ans=="Y"):
        v=[[6,1],[13,1],[16,4],[13,7],[6,7],[3,4]]
        graph="""-----@######@-------\n----#--------#------\n---#----------#-----\n--@------------@----\n---#----------#-----\n----#--------#------\n-----@######@-------\n"""
        print(graph)
        for i in v:
            print(f"({i[0]},{i[1]})",end=" ")
    
    elif(ans=="n" or ans=="N"):
        n=int(input("Please input the number of points:\n"))
        if(n==0):
            raise ValueError("You entered 0!")
        for i in range(n):
            a=input(f"Input X and Y of No.{i+1} point:(eg:X Y)\n").split()
            v.append([int(a[0]),int(a[1])])
        
    else:
        raise ValueError("Sorry, this option is not available!")
    #Determine whether it is a graph polygon
    if(not isConvex(v)):
        raise ValueError("The polygon you entered is not convex! Please confirm whether to input in order!")
    t=[]
    s=[]
    n=len(v)
    #initialization
    for i in range(n):
        t.append([0]*(n))
        s.append([0]*(n))
    minWeightTriangulation(n-1,t,s,v)
    traceback(s,0,n-1)

if __name__=="__main__":
    #exception handling
    try:
        main()
    except Exception as e:
        print("Your input is illegal! The error message is as follows:")
        print(e)

Determine whether it is a convex polygon

PYTHON
#Determine whether it is a convex polygon
'''
Calculate line expression
param vertex1: Previous vertex
param vertex2: Last vertex
return (type, param): Returns the category of the line and its description parameters
'''
def kb(vertex1, vertex2):
    x1 = vertex1[0]
    y1 = vertex1[1]
    x2 = vertex2[0]
    y2 = vertex2[1]
    
    if x1==x2:
        return (0, x1)      # 0-vertical line
    if y1==y2:              
        return (1, y1)      # 1 - horizontal straight line
    else:
        k = (y1-y2)/(x1-x2)
        b = y1 - k*x1
        return (2, k, b)    # 2-inclined straight line

'''
Determine whether it is a convex polygon
param vertexes: A list of all vertex coordinates that make up the polygon, such as[[0,0], [50, 0], [0, 50]]
return convex: Boolean type, is True Indicates that the polygon is convex, otherwise it is concave
'''
def isConvex(vertexes):
    # The default is convex polygon
    convex = True   
    
    # The polygon contains at least three vertices
    l = len(vertexes)
    if l<3:
        raise ValueError("Polygon contains at least three vertices!")
    
    # Judge the straight line composed of every two points
    for i in range(l):
        pre = i
        nex = (i+1)%l
        
        # Get a straight line
        line = kb(vertexes[pre], vertexes[nex])
        
        # Calculate the distance (either positive or negative) between all points and lines
        if line[0]==0:
            offset = [vertex[0]-vertexes[pre][0] for vertex in vertexes]
        elif line[0]==1:
            offset = [vertex[1]-vertexes[pre][1] for vertex in vertexes]
        else:
            k, b = line[1], line[2]
            offset = [k*vertex[0]+b-vertex[1] for vertex in vertexes]
        
        # Calculate the product of two distances. If there is a negative number, there are two points on both sides of the line, so it is a concave polygon
        for o in offset:
            for s in offset:
                if o*s<0:
                    convex = False
                    break
            if convex==False:
                break
                    
        if convex==False:
            break
            
    # Print judgment results
    if convex==True:
        print("The polygon is convex!")
    else:
        print("The polygon is concave!")
    
    return convex

3.9 0-1 knapsack problem

Where m(i,j) refers to the optimal value of 0-1 knapsack problem when the knapsack capacity is j and the optional items are i, i+1, ····, n

PYTHON
"""
Copyright: Copyright (c) 2019
Author: Justlovesmile
Title: 0-1 knapsack problem --dynamic programming
"""

#Jump point method
def knapsack_Pro(n,v,w,C,p,x):
    #head points to the beginning of the set of jump points at each stage
    head=[0 for i in range(n+1)]
    p[0][0],p[0][1]=0,0
    left,right,pnext,head[1]=0,0,1,1
    for i in range(n):
        k=left
        for j in range(left,right+1):
            if(p[j][0]+w[i]>C):
                break 
            y=p[j][0]+w[i]
            m=p[j][1]+v[i]
            #Jump points with weight less than this number are added directly and will not be dominated
            while(k<=right and p[k][0]<y):
                p[pnext][0]=p[k][0]
                p[pnext][1]=p[k][1]
                pnext+=1
                k+=1
            #Two IFS judge whether the newly generated point can be added to p
            if(k<=right and p[k][0]==y):
                if(m<p[k][1]):
                    m=p[k][1]
                k+=1
            if(m>p[pnext-1][1]):
                p[pnext][0]=y
                p[pnext][1]=m
                pnext+=1
            #Take out the controllable points
            while(k<=right and p[k][1]<=p[pnext-1][1]):
                k+=1

        #After break ing above
        while(k<=right):
            p[pnext][0]=p[k][0]
            p[pnext][1]=p[k][1]
            pnext+=1
            k+=1
        
        left=right+1
        right=pnext-1
        head[i+1]=pnext
    traceback_Pro(n,w,v,p,head,x)

def traceback_Pro(n,w,v,p,head,x):
    j=p[head[n]-1][0]
    m=p[head[n]-1][1]
    print("max value:",m,"max weight:",j)
    for i in range(n)[::-1]:
        for k in range(head[i],head[i+1]-1):
            if(p[k][0]+w[i]==j and p[k][1]+v[i]==m):
                x[i]=1
                j=p[k][0]
                m=p[k][1]
                break


def knapsack(v,w,C,m):
    #m[i][j] means that the backpack capacity is j, and the optional items are I, i+1, Optimal value of 0-1 knapsack problem with n
    n=len(v)-1
    #There is only one item left
    for j in range(C):
        m[n][j] = v[n] if j>=min(w[n]-1,C) else 0
    #General situation
    for i in range(1,n)[::-1]:
        for j in range(C):
            m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i]) if j>w[i]-1 else m[i+1][j]
    #First item
    if(n>0):
        m[0][C-1]=m[1][C-1]
        if C-1>=w[0]:
            m[0][C-1]=max(m[0][C-1],m[1][C-1-w[0]]+v[0])

def traceback(m,w,C,x):
    c=C-1
    for i in range(len(w)-1):
        #If no item I is selected, x[i]=0
        if (m[i][c]==m[i+1][c]):
            x[i]=0
        else:
            x[i]=1
            c -= w[i]
    #For the last item
    x[len(w)-1]=1 if m[len(w)-1][c]>0 else 0

#Output format
def cout(x,v,w):
    total_v=0
    total_w=0
    print("Choose:")
    for i in range(len(v)):
        if x[i]==1:
            print(f"No.{i+1} item: value is {v[i]} , weight is {w[i]}")
            total_v +=v[i]
            total_w +=w[i]
    print(f"total value: {total_v}")
    print(f"total weight: {total_w}")

def main():
    v=[]    #Value list of items
    w=[]    #Weight list of items
    #Enter item quantity
    n=input("Please input the number of items:\n")
    if(n=="" or n=="0"):
        raise ValueError("You have entered a null value or 0!")
    else:
        n=int(n)
    x=[0 for i in range(n+1)]
    #Choose two algorithms (in the textbook)
    ans=input("Choose Knapsack or Knapsack_Pro?(1 or 2)\n").split()[0]
    if ans=='1':
        m=[]    #m(i,j) means that the backpack capacity is j, and the optional items are i, i+1, Optimal value of 0-1 knapsack problem with n
        for i in range(n):
            item=input(f"please input No.{i+1} item's value(v) and weight(w):(eg:v w)\n").split()
            v.append(int(item[0]))
            w.append(int(item[1]))
        C=int(input("Please input the max weight of bag:\n"))
        if(C<=0):
            raise ValueError("Backpack capacity cannot be≤0")
        for i in range(n):
            m.append([0]*C)
        knapsack(v,w,C,m)
        traceback(m,w,C,x)
        cout(x,v,w)
    elif ans=='2':
        for i in range(n):
            item=input(f"please input No.{i+1} item's value(v) and weight(w):(eg:v w)\n").split()
            v.append(float(item[0]))
            w.append(float(item[1]))
        #initialization
        p=[[0 for i in range(2)]for j in range(n*n)]
        C=float(input("Please input the max weight of bag:\n"))
        if(C<=0):
            raise ValueError("Backpack capacity cannot be less than or equal to 0")
        if(n==1):
            if(w[0]<=C):
                x[0]=1
            else:
                x[0]=0
        else:
            knapsack_Pro(n,v,w,C,p,x)
        for i in range(n):
            if(x[i]==1):
                print("choose: value:",v[i],"weight:",w[i])
    else:
        raise ValueError(f"You entered{ans}This option is not available!")

if __name__=="__main__":
    #exception handling
    try:
        main()
    except Exception as e:
        print("Your input is illegal! The error message is as follows:")
        print(e)

3.10 optimal binary search tree

Binary search tree: the element x stored in each node is greater than the element stored in any node in its left subtree and less than the element stored in any node in its right subtree

Chapter 4 greedy algorithm

Greedy algorithm: it always makes the best choice at present, that is, the greedy algorithm does not consider the overall optimization, and its choice is only the local optimal choice in a sense.

The greedy algorithm shall meet the following requirements:

Greedy selectivity: it means that the overall optimal solution of the problem can be achieved through a series of local optimal choices, that is, greedy selection

Optimal substructure property: when the optimal solution of a problem contains the optimal solution of its subproblem, the problem is said to have the optimal substructure property

The problem for which the greedy algorithm is suitable: there are n inputs, and the solution consists of a subset of the N inputs that meet some predetermined constraints, and the subset that meets the constraints is called the feasible solution of the problem. Obviously, the feasible solution is not unique in general. Those feasible solutions that make the objective function take the extreme value become the optimal solution.

Greedy algorithm is a hierarchical processing method. It first selects a metric according to the meaning of the problem, then sorts the n inputs according to this metric, and inputs them in order. If the conditions are not met, the input will not be added to the solution.

The core problem of greedy algorithm design and solution is to select the optimal measurement standard that can produce the optimal solution of the problem.

Proof of correctness of greedy algorithm:

① It is proved that the problem solved by the algorithm has an optimal substructure

② It is proved that the problem solved by the algorithm is greedy and selective

③ The algorithm makes local optimal selection according to the greedy selectivity of ②

4.2 activity arrangement

In order to select the most compatible activities, the activity with the smallest fi is selected each time, so that more activities can be selected

Metrics: in non decreasing order of end time

If ordered, O(n), if disordered, O(nlogn)

"""
Copyright: Copyright (c) 2019
Author: Justlovesmile
Title: Activity arrangement
"""

#Activity class, each activity includes start time and end time
class activity():
    def __init__(self,ss,ff):
        self.s=ss
        self.f=ff
    

def greedySelector(arr,a):
    n=len(arr)-1
    a[0]=True
    j=0
    count=1
    #Join with start time greater than the end time of the previous activity (set to True)
    #O(n)
    for i in range(1,n+1):
        if(arr[i].s>=arr[j].f):
            a[i]=True
            j=i
            count+=1
        else:
            a[i]=False
    return count

def main():
    activities=[]
    #input data
    n=int(input("please input the number of activities:\n"))
    #exception handling
    if(n==0):
        raise ValueError("You entered 0!")
    print("Use greedy selector , activities should be ordered by the end_time.")
    for i in range(n):
        item=input("please input the begin-time and end-time:(eg: 3 6)\n").split()
        if(len(item)!=2):
            raise ValueError("The number of data you entered is illegal!")
        s=activity(float(item[0]),float(item[1])) 
        activities.append(s)
    #Sort by end time in non decreasing order
    activities=sorted(activities,key=lambda x:x.f)
    #Initialize selection set a
    a=[False for i in range(n)]
    count=greedySelector(activities,a)
    print("Maximum number of activities:",count)
    print("Choose:",a)

if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print("Your input is illegal! The error message is as follows:")
        print(e)

Author: justrovesmile

Link: https://blog.justlovesmile.top/posts/16050.html

Source: justrovesmile's blog

The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.