(学习10)贪心算法之相容问题

问题描述

相容问题:有一个礼堂需要用于举办活动,每个活动有开始时间与结束时间;如果任何两个活动不能在礼堂中同时进行,问如何选择这些活动,使得能在礼堂中安排最多活动;

解析:

贪心策略1:活动按照结束时间进行升序排序:

从第一个活动开始向后选择,若当前活动与前一个活动相容(fi-1<=si)

活动序号 i

1

2

3

4

5

6

开始时间si

1

2

2

4

6

8

结束世界fi

2

3

4

6

12

12

选择活动1:这是结束最早的活动

选择活动2:因为s2==f1,与活动1相容,即纳入安排

不选择活动3:因为s3<f2,与活动2不相容,所以不纳入安排

选择活动4:因为s4>f2,与活动2相容,所以纳入安排

选择活动5:因为s5>f4,与活动4相容,所以纳入安排

选择活动6:因为s6<f5,与活动5相容,所以纳入安排

 策略一在这个问题上被证明是可行正确的,具体证明较为复杂,可以自行研究

贪心策略2:按照开始时间进行排序:

活动序号 i

1

2

3

4

5

6

开始时间si

1

2

2

4

6

8

结束世界fi

2

3

4

6

12

12

选择活动1:这是结束最早的活动

选择活动2:因为s2==f1,与活动1相容,即纳入安排

不选择活动3:因为s3<f2,与活动2不相容,所以不纳入安排

选择活动4:因为s4>f2,与活动2相容,所以纳入安排

选择活动5:因为s5>f4,与活动4相容,所以纳入安排

不选择活动6:因为s6<f5,与活动5不相容,所以不纳入安排

 

 

反例:

活动序号 i

1

2

3

4

5

6

7

开始时间si

1

1

2

2

4

5

6

结束世界fi

2

3

3

4

7

6

8

 

而最优策略:

活动序号 i

1

2

3

4

5

6

7

开始时间si

1

1

2

2

4

5

6

结束世界fi

2

3

3

4

7

6

8

 

 

贪心策略3:按照活动时间进行排序:

活动序号 i

1

2

3

4

5

6

开始时间si

1

2

2

4

8

6

结束世界fi

2

3

4

6

12

12

 

选择活动1:这是活动时间最少的活动

选择活动2:因为s2==f1,与活动1相容,即纳入安排

不选择活动3:因为s3<f2,与活动2不相容,所以不纳入安排

选择活动4:因为s4>f2,与活动2相容,所以纳入安排

选择活动5:因为s5>f4,与活动4相容,所以纳入安排

不选择活动6:因为s6<f5,与活动5不相容,所以不纳入安排

 

贪心策略3反例:

活动序号 i

1

2

3

开始时间si

7

4

8

结束世界fi

9

8

14

 

而最优策略:

 

活动序号 i

1

2

3

开始时间si

7

4

8

结束世界fi

9

8

14

 

针对策略一的伪代码设计

S={1};
//还需对活动按照结束时间进行升序排序
for (i=2;i<=n;i++){ if si>=fj{ append(S,i);//将该活动放到集合S中 j=i; } } return S;

 

复杂度分析:O(nlogn)

源代码:

//
//  main.cpp
//  作业10
//
//  Created by yizhihenpidehou on 2020/4/28.
//  Copyright © 2020 yizhihenpidehou. All rights reserved.
//

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
struct A{
    int s;//开始时间
    int e;//结束时间
}Act[200];
bool cmp(struct A a,struct A b){
    return a.e<b.e;
}
void greedy(struct A* a,int n,int ap[]){
    sort(a+1,a+1+n,cmp);
    ap[1]=1;
    int j=1;//记录最新纳入计划的活动的序号
    int count=1;//记录有几个活动纳入计划
    for(int i=2;i<=n;i++){
        if(a[i].s>=a[j].e){//若当前活动与已纳入的最新活动兼容,则纳入计划
            ap[++count]=i;
            j=i;
        }
    }
    for(int i=1;i<=count;i++){
        printf("%d ",ap[i]);
    }
    printf("\n");
}
int main(int argc, const char * argv[]) {
    Act[1].s=1;Act[1].e=2;
    Act[2].s=2;Act[2].e=3;
    Act[3].s=2;Act[3].e=4;
    Act[4].s=4;Act[4].e=6;
    Act[5].s=8;Act[5].e=12;
    Act[6].s=6;Act[6].e=12;
    int ap[200]={0};
    greedy(Act,6,ap);
    return 0;
}
View Code

 

 

posted @ 2020-04-28 20:15  一只很皮的猴猴  阅读(431)  评论(0编辑  收藏  举报