算法导论16.13 区间图着色(intervalgraph coloring)问题(贪心算法)

CLRS 16.1-3 假设要用很多个教室对一组活动进行调度。我们希望使用尽可能少的教室来调度所有的活动。请给出一个有效的贪心算法,来确定哪一个活动应使用哪一个教室。

(这个问题也被成为区间图着色(interval-graph coloring)问题。我们可作出一个区间图,其顶点为已知的活动,其边连接着不兼容的活动。为使任两个相邻结点的颜色均不相同,所需的最少颜色对应于找出调度给定的所有活动所需的最少教室数。)

方法一:
我们很容易就可以想到用P227页的GREEDY-ACTIVITY-SELECTOR(s, f)来解决这个问题,首先调用这个函数,得到可以兼容的最大活动数,然后再在余下的活动中再次调用这个函数,直至活动为0。 见代码清单-1

方法二:
1.对于所有活动的时间点按升序进行排序(n个活动,就有2n个时间点),记录每个时间是起始的还是终止的,在排序的时候,对于值相同的时间点,如果是终止时间点的话,就排在前面。
2.最开始,选择第一个起始时间点,把它对应的活动放入一个教室,同时记录这个起始时间点对应的终止时间点。
3.接着按序选择第i个起始时间点(只选择起始时间点),对于第i个起始时间点,比较它和已有教室中的活动的终止时间点,若大于某个终止时间点,则直接将第i个起始时间点对应的活动放进相应的教室,否则新开辟一个教室来放入这个活动。 见代码清单-2

对于区间图着色(interval-graph coloring)问题,先在一个集合中放入一个点,然后把不与这个点相邻的所有元素放入这个集合,对于剩下的点,重复前面的动作即可,依此循环,直至没有点可选。最后,有多少个集合就是多少种颜色,集合中的元素用相同的色渲染。

代码清单-1:

View Code
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 //活动
 5 typedef struct activity_t
 6 {
 7   int start;//起始时间
 8   int end;//结束时间
 9 } activity;
10 
11 //和P227页的算法思路相同
12 void greedy_algorithm(activity* data, const int n)
13 {
14   if (n > 0)
15   {
16     int sequence[n];
17     int i;
18     for (i = 0; i < n; i++)
19       sequence[i] = -1;
20     i = 0;
21     sequence[i] = 0;
22     int count = 0;
23     int tmp = 0;
24     while ((++count) < n)
25       {
26     if (data[count].start >= data[tmp].end)
27       {
28         sequence[++i] = count;
29         tmp = count;
30       }
31       }
32     int j;
33     for (j = 0; j < n; j++)
34       {
35     if (sequence[j] == -1)
36       break;
37     printf("[%d,%d)\t", data[sequence[j]].start, data[sequence[j]].end);
38       }
39     printf("\n----------\n");
40 
41     //对于剩下的数据再调用本函数
42     activity* remain_data = (activity*)malloc(sizeof(activity)*(n-j));
43     int p;
44     int q;
45     int k = 0;
46     for (p = 0; p < n; p++)
47       {
48     int flag = 0;
49     for (q = 0; q < j; q++)
50       {
51         if (p == sequence[q])
52           {
53         flag = 1;
54         break;
55           }
56       }
57     if (flag == 0)
58       {
59         remain_data[k++] = data[p];
60       }
61       }
62     greedy_algorithm(remain_data, n-j);
63     free(remain_data);
64   }
65 }
66 
67 int main()
68 {
69   int n;
70   scanf("%d", &n);
71   activity* data = (activity*)malloc(n*sizeof(activity));
72   activity a;
73   int rows = n;
74   //按照结束时间从小到大进行输入,P222页底下表格中的数据
75   while (rows--)
76   {
77     scanf("%d%d", &(a.start), &(a.end));
78     data[n-rows-1] = a;
79   }
80   greedy_algorithm(data, n);
81   free(data);
82   return 0;
83 }

代码清单-2:

View Code
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 //每个时间点;是起始时间,还是终止时间;及其对应的结束时间
 5 typedef struct point_t
 6 {
 7   int time;
 8   int is_start;
 9   int end_time;//若is_start为1,end_time写对应的时间;若is_start为0,end_time为-1
10 } point;
11 
12 //升序排列,若时间相同,则为终止时间的时间点排在前面
13 int compare(const void* a, const void* b)
14 {
15   if ((*(point*)a).time != (*(point*)b).time)
16     return (*(point*)a).time > (*(point*)b).time;
17   else 
18     return (*(point*)a).is_start < (*(point*)b).is_start;//这里得用小于
19 }
20 
21 void process(point* points, const int n)
22 {
23   //排序
24   qsort(points, n, sizeof(point), compare);
25   //最多n/2个教室
26   int classrooms[n/2];
27   int count = 0;
28   classrooms[count++] = points[0].end_time;
29   printf("[%d, %d)在教室%d\n", points[0].time, points[0].end_time, count);
30   int i;
31   int j;
32   for (i = 1; i < n; i++)
33   {
34     if (points[i].is_start == 1)
35     {
36       for (j = 0; j < count; j++)
37       {
38     if (classrooms[j] <= points[i].time)
39     {
40       classrooms[j] = points[i].end_time;
41       printf("[%d, %d)在教室%d\n", points[i].time, points[i].end_time, j+1);
42       break;
43     }
44       }
45       if (j == count)
46       {
47     classrooms[count++] = points[i].end_time;
48     printf("[%d, %d)在教室%d\n", points[i].time, points[i].end_time, count);
49       }
50     }
51   }
52   printf("总共需要%d个教室.\n", count);
53 }
54 
55 int main()
56 {
57   int rows;
58   scanf("%d", &rows);
59   //2*rows个点
60   point* points = (point*)malloc(2*rows*sizeof(point));
61   //point p;
62   int n = rows;
63   //point p;
64   int start_time;
65   int end_time;
66   while (rows--)
67   {
68     int id = n - rows - 1;
69     scanf("%d%d", &start_time, &end_time);
70     point p1;
71     p1.is_start = 1;
72     p1.time = start_time;
73     p1.end_time = end_time;
74     points[2*id] = p1;    
75     
76     point p2;
77     p2.is_start = 0;
78     p2.time = end_time;
79     p2.end_time = -1;
80     points[2*id + 1] = p2;
81   }
82   process(points, 2*n);
83   free(points);
84   return 0;
85 }

输入数据为:

11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14
原文地址:https://www.cnblogs.com/null00/p/2499863.html