贪心算法区间图着色问题

问题来自算法导论十六章,使用尽可能少的教室对一系列活动进行调度。
思路,把能兼容的活动放在以一个教室。
先把所有活动按结束时间递增的顺序排列,方便以后的循环。选取快速排序,期望时间复杂度为nlgn,最坏为n^2.快排我都有点忘记了,但是看了一下算法导论的图就秒懂了,可见学算法结合图形还是很重要的事情。
循环活动,把每个活动往教室里填,看活动是否与教室里已有的活动兼容(也就是开始时间是否比最后一个活动的结束时间更晚),如果兼容,就填进教室里去,如果不兼容,就新开一个教室存放该活动。继续循环。

代码如下,注释很详细。参考了一位博主的代码,现在找不到他那个页面了,见谅…..该博主用了结构体,这个问题确实很适合用结构体,在一个活动中有开始时间结束时间然后表状态,记录选择。不用去定义很多数组再一一对应。学习学习



#include "stdafx.h"
#include<stdio.h>
# define N 100

struct Activity
{
    int number;            //活动编号
    int begin;           //活动开始时间
    int end;            //活动结束时间
    bool flag;          //此活动是否被选择
    int roomnum;      //此活动在哪间教室举行
};


//对于活动集,按照结束时间递增排序,使用快速排序
void quicksort(Activity *a, int p, int r)
{
    if (p < r)
    {
        int i = p- 1,j=p;
        Activity aa = a[r];
        while (j < r)                              //这个while循环是在将数组划分为小于最后一个元素,大于最后一个元素和最后一个元素三部分。
        {
            if (a[j].end <= aa.end)                 
            {
                i++;                            //i总是指向第一个区域的最后一个元素,然后i++去占领新的位置。j始终指向第二个区域的最后一个元素的下一个元素,也就是即将归类的新元素
                Activity t = a[i];
                a[i] = a[j];
                a[j] = t;
            }
            j++;
        }
        Activity t = a[r];               //以下三行的交换是为了把最后一个元素提到他应该有的位置
        a[r] = a[i + 1];
        a[i + 1] = t;
        quicksort(a, p, i);
        quicksort(a, i + 1, r);
    }
}


int select_room(Activity *a, int *time, int n)
{
    int i = 1, j = 1;
                            //下面初始化数据,把第一个活动安排了,然后循环从第二个活动开始
    int sumroom=1;        //已经占用的教室,计算然后返回最终值
    int sumact=1;           //已经被选择的活动,初始化为1
    time[1] = a[0].end;      //初始化教室1的最后一个活动的结束时间为活动1的结束时间
    a[0].roomnum = 1;         //将第一个活动占用的教室初始化为教室1
    for (i = 1; i < n; i++)                   //遍历i个活动
    { 
         for(j=1;j<=sumroom;j++)                    //遍历j个教室,把活动i放进哪个教室
            if (a[i].begin >= time[j] && (!a[i].flag))          //活动i开始的时间比教室j最后一个活动的结束时间晚,且活动i没有被规划过。那么就应该吧活动i划入教室j
            {                                                   //进行一波更新
                a[i].roomnum = j;
                a[i].flag = true;
                time[j] = a[i].end;
                sumact++;
            }
         if (sumact < n&&i == n - 1)             //已经把一间教室能加入的活动搞完了,活动i不能已有加入教室,那么它就自己新开一间教室
         {
             i = 0;                              //控制重新遍历的条件
             sumroom++;
         }
    }
    return sumroom;
}

int main()
{
    Activity a[N];          //定义一个结构体
    int time[N];            //time 用于记录某个教室里面末尾活动的结束时间,方便与下一个活动的开始时间比较
    int n,i=0,j;                  //输入的活动个数
    int sum;
    int k = 0;
    printf("输入活动个数:\n");
    scanf_s("%d", &n);
    for (i = 0; i < n; i++)
    {
        time[i + 1] = 0;
        a[i].number = i + 1;
        a[i].flag = false;
        a[i].roomnum = 0;      
        printf("输入活动%d的开始时间:", ++k);
        scanf_s("%d", &a[i].begin);
        printf("输入活动%d的结束时间:", k);
        scanf_s("%d", &a[i].end);

    }
    quicksort(a, 0, n - 1);
    sum = select_room(a, time, n);
    printf("所占教室总数目是:%d\n", sum);
    for (i = 0; i < n; i++)
        printf("活动%d在教室%d中\n", a[i].number, a[i].roomnum);
}

猜你喜欢

转载自blog.csdn.net/alike_meng/article/details/82593546