算法导论16.1-3 区间图着色(interval-graph 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:
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:
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
可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明