版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36718838/article/details/82179147
a情况
比如S12就是i>=j-1,S12表示a1活动结束之后,a2活动开始之前的活动集合,显然这a1,a2之间并没有活动。i比j大就是非正常情况了。
b情况
存在活动时,c[i,j]=max{c[i,k]+c[k,j]+1} k就是用来分解成子问题的其中一个活动ak,用于遍历,+1是因为结果需要加上ak自身。
1.动态规划-自底向下
namespace Code5
{
class Program
{
static void Main(string[] args)
{
int[] s = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12, 24 };
int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 24 };
List<int>[,] result = new List<int>[13, 13];// 默认值null
for (int m = 0; m < 13; m++)
{
for (int n = 0; n < 13; n++)
{
result[m, n] = new List<int>();//构造result
}
}//默认值就是空list集合
//两层循环遍历每个区间情况
for (int j = 0; j < 13; j++)//从j=2开始
{
for (int i = 0; i < j - 1; i++)//从i=0开始
{
// S[ij] i结束之后 j开始之前的 活动集合
// f[i] s[j] 这个时间区间内的所有活动
List<int> sij = new List<int>();
//number 活动编号,最后一个24不算在内所以要-1
for (int number = 1; number < s.Length - 1; number++)
{
//遍历每个活动,判断哪个活动的时间在区间内
if (s[number] >= f[i] && f[number] <= s[j])
{
sij.Add(number);
}
}
if (sij.Count > 0)//区间内有活动可以加入的情况下
{
//result[i,j]=max{ result[i,k]+result[k,j]+ k }
int maxCount = 0;
List<int> tempList = new List<int>();//保存最大兼容子集
foreach (int k in sij)
{
int count = result[i, k].Count + result[k, j].Count + 1;
if (maxCount < count)
{
maxCount = count;
//Union 获得并集
tempList =
result[i, k].Union<int>(result[k, j]).ToList<int>();
tempList.Add(k);
}
}
result[i, j] = tempList;
}
}
}
List<int> l = result[0, 12];
foreach (int temp in l)
{
Console.WriteLine(temp);
}
Console.ReadKey();
}
}
}
2.贪心算法
活动时间是按照结束时间进行排序的。获得第一个最早结束的活动之后,第一个活动的结束时间f[1],下一个活动就是找一个开始时间s[n]<f[1]且结束时间最早的活动。
比如 a[1]的时间是[1,4] 下一个活动只能是从4开始。可以从表中看到a[4],a[6],a[7],a[8],a[9],a[11]都是在4之后开始的。此时找出这些活动中最早结束的,就是第二个被安排的活动。也就是a[5]。同理继续查找就会找到a[8],a[11]。结果与上面动态规划得出的结果相同。
递归解决
namespace Code5
{
class Program
{
static void Main(string[] args)
{
List<int> list = ActivitySelection(1, 11, 0, 24);
foreach (int temp in list)
{
Console.WriteLine(temp);
}
Console.ReadKey();
}
static int[] s = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
static int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
/// <summary>
/// 活动选择方法
/// </summary>
/// <param name="startActivityNumber">开始活动编号</param>
/// <param name="endActivityNumber">结束活动编号</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <returns></returns>
public static List<int> ActivitySelection
(int startActivityNumber, int endActivityNumber, int startTime, int endTime)
{
//递归结束条件
if (startActivityNumber > endActivityNumber || startTime >= endTime)
{
return new List<int>();
}
//找到结束时间最早的活动
int tempNumber = 0;
for (int number = startActivityNumber; number <= endActivityNumber; number++)
{
if (s[number] >= startTime && f[number] <= endTime)
{
tempNumber = number;
break;
}
}
//返回剩余的部分的 最大兼容子集
List<int> list =
ActivitySelection(tempNumber + 1, endActivityNumber, f[tempNumber], endTime);
list.Add(tempNumber);//加入这个最早的活动
return list;
}
}
}
迭代解决
namespace Code5
{
class Program
{
static void Main(string[] args)
{
int[] s = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
int startTime = 0;
int endTime = 24;
List<int> list = new List<int>();
for (int number = 1; number <= 11; number++)
{
if (s[number] >= startTime && f[number] <= endTime)
{
list.Add(number);
startTime = f[number];
}
}
foreach (int i in list)
{
Console.WriteLine(i);
}
Console.ReadKey();
}
}
}