算法導論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:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM