Problema de selección de actividades | Codicioso

Al programar múltiples actividades con recursos compartidos, el objetivo es seleccionar el mayor conjunto de actividades compatibles entre sí.

Hay un conjunto de n actividades S = {a1, a2, ..., an}, y cada actividad tiene una hora de inicio si y una hora de finalización fi. Las actividades que no se superponen entre sí en períodos de tiempo son compatibles entre sí, y se selecciona un subconjunto de las actividades compatibles más grandes.


1. Idea de algoritmo

Se registra \ bg_white S_k = \ left \ {a_i \ epsilon S | s_i> f_k \ right \}como el conjunto de tareas que comienzan después del final de ak, y obviamente tiene el siguiente teorema:

Teorema 1: Considere una pregunta arbitraria no vacía S_k, por lo que a.mes S_kel final de la actividad más antigua, a.men S_kel caso de un subconjunto compatible máximo,

Primero, el período de tiempo de cada actividad debe ordenarse según la hora de finalización (orden creciente). 

De forma intuitiva, deberíamos seleccionar una actividad de este tipo cada vez, y los recursos restantes después de seleccionarla deberían usarse para tantas otras tareas como sea posible. Por lo tanto, se toma una decisión codiciosa : cada vez que se selecciona y finaliza antes la actividad que es compatible con el subconjunto, se agrega al subconjunto. Conocido por el teorema 1: este resultado debe ser un subconjunto de la actividad compatible más grande (no única).


Dos, implementación de algoritmo

1. Implementación recursiva

#define MAXN
bool isSelected[MAXN] = {false};   //标记是否加入最终的子集

/* 开始时间与结束时间对应存储在数组s、f中(已经按结束时间增序排序好)
 * 在第 k + 1 ~ n个活动间选择:子问题大小为 Sk 
 * 选取结果存储在 isSelected 数组中*/
void RecursiveActivitySelector(int s[], int f[], int k, int n) {
    int m = k + 1;   //开始寻找活动的起点
    while (m <= n && s[m] < f[k])
        m++;   //在范围内找到合适的 m
    if (m <= n) {
        isSelected[m] = true;  //选择第 m个活动
        RecursiveActivitySelector(s, f, m, n);
    }
}

2. Realización recursiva 

#define MAXN
bool isSelected[MAXN] = {false};   //标记是否加入最终的子集
/* 开始时间与结束时间对应存储在数组s、f中(已经按结束时间增序排序好)
 * 活动个数为 n
 * 选取结果存储在 isSelected 数组中 */
void GreedyActivitySelector(int s[], int f[], int n) {
    int temp = 1;  //当前选取的活动
    isSelected[temp] = true;
    for(int i = 2; i <=n; i++) {
        /* 找到合适的 */
        if(s[i] >= f[temp]) { 
            temp = i;  //选择
            isSelected[temp] = true;
        }
    }
}

Tres, otro

Hay un conjunto de n actividades S = {a1, a2, ..., an}, y cada actividad tiene una hora de inicio si y una hora de finalización fi. Necesitamos organizarlos en algunas aulas, ¿cuántas aulas se requieren al menos?


Idea 1: algoritmo codicioso

       Esta pregunta es una extensión de la pregunta anterior. Puede seleccionar un subconjunto de las actividades compatibles más grandes en S (equivalente a asignarlas a un aula) y luego eliminar estas actividades seleccionadas de S, continuar eligiendo ... Hasta que se seleccionen todas las actividades en S, solo vea cuántas aulas se asignan.


Idea 2: algoritmo de simulación

      Simule directamente el uso del aula: coloque la hora de inicio sy la hora de finalización f juntas en orden creciente, y la hora de finalización tiene una mayor prioridad (cuando la hora es la misma, la hora de finalización se clasifica antes de la hora de inicio). Atraviese este punto de tiempo ordenado a su vez, aula ++ cuando encuentre la hora de inicio y aula, cuando encuentre la hora de finalización. Mantenga un max_classroom en el medio, registre el valor máximo del aula, que es la respuesta final.

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43787043/article/details/105412113
Recomendado
Clasificación