随笔-80  评论-24  文章-0  trackbacks-0
该问题是一个经典问题,算法导论中的例题。
题意是有若干个会议要开,每个会议给定开始时间s和结束时间e,其中任意两个会议i和j,若i的时间和j的时间有重叠(包括边界相等情况),则认为两个会议不能同时进行即冲突,现在要问给定若干个会议,求最多能有多少会议不冲突,即最大会议兼容子集的大小。
标准的贪心算法,可以先按照会议结束时间排序,然后再依次考虑每个会议。算导上的证明非常精彩,强烈建议捧读。
简单来说就是利用了一个定理:
对于任意非空子问题Sij,其中Sij代表会议i到j的集合,设am是Sij中具有最早结束时间的会议,则会议am在Sij的最大兼容会议子集中被使用。
其实该定理就是说明为什么按照会议结束时间排序再依次考虑每个会议就能得出最优解。
该定理是这样被证明的:设Aij为Sij的最大兼容会议子集,且将Aij中的会议按照结束时间递增排序。又设ak为Aij的第一个回忆。若ak = am,则定理得证;否则若ak != am,则因为am是Sij中结束时间最早的会议,所以am.finish <= ak.finish,这样肯定可以构造新的兼容会议子集,Bij = (Aij - ak∪ am。而该子集包含的会议个数是和Aij的会议个数相等的!这就证明了am肯定包含在了Sij的最大兼容会议子集中。
样题见
http://acm.nyist.net/JudgeOnline/problem.php?pid=14
代码如下:

 1 #include <cstdio>
 2 #include <cstdlib>
 3 
 4 #define MAX_EVENT 10005
 5 
 6 struct EVENT {
 7   int start;
 8   int finish;
 9 };
10 
11 EVENT event[MAX_EVENT];
12 
13 static int cmp(const void *a, const void *b) {
14   EVENT *p = (EVENT *)a;
15   EVENT *q = (EVENT *)b;
16   return p->finish > q->finish;
17 }
18 
19 int main() {
20   int m;
21   int n;
22   scanf("%d", &m);
23   while (m--) {
24     scanf("%d", &n);
25     int i;
26     for (i = 0; i < n; ++i) {
27       scanf("%d%d", &(event[i].start), &(event[i].finish));
28     }   
29     qsort(event, n, sizeof(EVENT), cmp);
30     int res = 1;
31     int max_finish = event[0].finish;
32     for (i = 1; i < n; ++i) {
33       if (event[i].start > max_finish) {
34         res++;
35         max_finish  = event[i].finish;
36       }   
37     }   
38     printf("%d\n", res);
39   }
40   return 0;
41 }

贪心算法和动态规划算法是算法领域非常重要的两类算法,需要好好掌握。
posted on 2012-09-16 12:32 myjfm 阅读(1398) 评论(0)  编辑 收藏 引用 所属分类: 算法基础

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理