Activity selection problem - greedy algorithm and dynamic programming

optimal substructure

Let Sij represent the activity set after the start time of activity i and before the end of activity j, suppose there is a maximum compatible activity subset Aij, which includes activity k. Since the optimal solution contains activity k, two subproblems can be obtained: finding a compatible subset of activities in Sik and Skj. The solution of the original problem becomes: Aij = Aik ∪k ∪Akj.

Having the optimal substructure means that it can be solved by dynamic programming.

If the size of the optimal solution of the set Sij is represented by c[i][j], the recursive formula can be obtained:

​ c[i][j] = c[i][k] + 1 + c[k][j]

The optimal solution is c[0][N+1].

Of course, if you don't know which activity k the optimal solution contains, you must examine all options k, so the optimal solution:

​ c[i][j] = max( c[i][k] + 1 + c[k][j] ) (Sij is not empty) (k = i+1….j-1 and k and before and after activity compatible)

​ = 0 (Sij is empty)

/*测试数据
    注意Sij表示的意义是活动i结束后,活动j结束前的兼容活动,所以是双开区间
    int s[] = { 0,1,3,0,5,3,5,6,8,8,2,12,_CRT_INT_MAX };
    int f[] = { 0,4,5,6,7,9,9,10,11,12,14,16,_CRT_INT_MAX };
*/
#define N 11
void dp_act(int s[], int f[])
{
    int i = 0;
    int c[N + 2][N + 2] = { 0 };
    for (int len = 2; len <= N+1; len++) {

        for (i = 0; i <= N -len+1; i++) {
            int j = i + len;
            //Sij不为空
            if (f[i] <= s[j]) {
                int maxn = -1;
                for (int k = i+1 ; k <j; k++) {
                    if (s[k] >= f[i] && f[k] <= s[j]) {
                        maxn = c[i][k] + c[k][j] + 1;
                        if (maxn > c[i][j]) {
                            c[i][j] = maxn;
                        }
                    }
                }

            }
        }
    }
}

recursive greedy form

The dynamic regression form examines all the processes of choosing k in the recursive formula. If greedy is used to select the earliest-ending activity, there is a sub-problem left to solve.

The difference between greedy algorithm and dynamic return:

A choice is made at each step of the return, but the choice depends on the solution of the subproblem. Therefore, a bottom-up solution is usually used, where the smaller sub-problems are solved first, and then the larger sub-problems are solved. In a greedy algorithm, the best choice at the time is always chosen, leaving the only subproblem to be solved, and the subproblem does not depend on any future choices.

Therefore, unlike dynamic regression to solve subproblems before making the first choice, greedy does not need to solve any subproblems before making the first choice.

Of course, we need to prove that each greedy choice produces a globally optimal solution.

int ret[10];
int ans = 0;
void recur_act_select(int s[], int f[], int k, int n)
{
    int m = k + 1;  //m是每次第一个结束的活动的下标
    while (m <= n && s[m] < f[k]) {
        m++;
    }
    if (m <= n) {
        ret[ans++] = m;
        return recur_act_select(s, f, m, n);
    }
    return;
}

iterate

Tail recursion is changed to iteration. The key is that each calculation result participates in the next calculation.

//尾递归改成循环
void gred_act_select(int s[], int f[], int n)
{
    int k = 0;
    int m = 0;
    int ret[10] = { 0 };
    int ans = 0;
    while (k <= n) {
        if (s[k] >= f[m]) {
            ret[ans++] = k;
            m = k;
        }
        k++;
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325904773&siteId=291194637