1.问题
设S={1,2,3,… ,n}为活动集合,s[i],f[i]分别为活动i的开始时间和结束时间,i=1,2,3,… ,n
规定相容的定义:(s[j]>=f[i] && i<j) || (s[i]>=f[j]&&i>j),求S最大的两两相容子集A
2.解析
因为使用贪心算法,所以有多项可供我们贪心,有开始时间,活动的时长,开始时间/结束时间,结束时间。
定义x-y的形式表示,某活动x开始,y结束。
(1)针对开始时间我们很容易可以举出反例,有样例1-10,3-4,5-6,7-8,9-10已经按照开始时间升序排列,如果按开始时间贪心,|A|=1,而最优情况显然为|A|=4,所以此贪心方式错误。
(2)针对活动时长,我们也可以举出反例,有样例7-10,4-8,9-13已经按活动时长升序排列,如果按照活动时长贪心,|A|=1,而最优情况显然为|A|=2,所以此贪心方式也错误。
(3)(开始时间/结束时间)和(2)类似,活动时长越小,比值越大,所以也行不通,不再赘述。
(4)最后让我们试试结束时间,将上面两个例子按结束时间升序排列,3-4,5-6,7-8,1-10,9-10,|A|=4,符合最优解;4-8,7-10,9-13,|A|=2,符合最优解,针对此贪心方式我暂时无法举出反例,所以可以尝试证明一下。此处证明参考老师上课的证明。
定理:对于任意正整数k,使用结束时间的贪心算法,前k步选择都会有一个最优解。
证明:k=1时,选择活动1,设
A
=
i
1
,
i
2
,
i
3
,
.
.
.
,
i
j
A={i_1,i_2,i_3,...,i_j}
A=i1,i2,i3,...,ij为问题最优解,如果i_1==1,则最优解包含1,如果i_1!=1,则可以通过替换得到
A
’
=
(
A
−
{
i
1
}
)
⋃
{
1
}
A’=(A-\{i_1\})\bigcup\{1\}
A’=(A−{i1})⋃{1},因此最优解包含活动1得证。
对于任意整数k,设S_B为剩余活动中与已选活动相容的活动,B为剩余活动中与已选活动相容的活动的最优解,则
A
=
{
i
1
,
i
2
,
.
.
.
,
i
k
}
⋃
B
A=\{i_1,i_2,...,i_k\} \bigcup B
A={i1,i2,...,ik}⋃B为最优解,若B不是S_B的最优解,那必然存在B’是S_B的最优解,则|B’|>|B|,那
A
′
′
=
{
i
1
,
i
2
,
.
.
.
,
i
k
}
⋃
B
′
A''=\{i_1,i_2,...,i_k\} \bigcup B'
A′′={i1,i2,...,ik}⋃B′,可以看出A’’比A项目数更多,与已知不符,所以B是S_B最优解。
综上所述,我们可以推出
A
=
{
1
,
i
2
,
i
3
,
.
.
.
,
i
k
}
⋃
B
A=\{1,i_2,i_3,...,i_k\} \bigcup B
A={1,i2,i3,...,ik}⋃B
=
{
1
,
i
2
,
i
3
,
.
.
.
,
i
k
}
⋃
{
i
(
k
+
1
)
,
.
.
.
.
.
.
}
= \{1,i_2,i_3,...,i_k\} \bigcup \{i_(k+1),......\}
={1,i2,i3,...,ik}⋃{i(k+1),......}
=
{
1
,
i
2
,
i
3
,
.
.
.
,
i
k
,
i
k
+
1
}
⋃
(
B
−
{
i
k
+
1
}
)
=\{1,i_2,i_3,...,i_k,i_{k+1}\} \bigcup(B-\{i_{k+1}\})
={1,i2,i3,...,ik,ik+1}⋃(B−{ik+1}),A包含了k+1项,得证。
3.设计
void solve(action ac[], int n)
{
sort(ac, ac + n);
action tmp[MAXN];
int cnt = 0;
tmp[0] = ac[0];
for (int i = 1; i < n; i++)
if (ac[i].s > tmp[cnt].f)
tmp[++cnt] = ac[i];
for (int i = 0; i <= cnt; i++)
printf("%d %d\n", tmp[i].s, tmp[i].f);
}
4.分析
时间复杂度:O(n)
*如果算上排序的话则是O(nlogn)