/*
* 题目大意: DP方法解活动选择问题
解题思路: s(i,j)表示所有活动的集合{fi <= sk < fk <= sj},即活动ai和aj之间,所有与这两个活动
兼容的活动组成的子集。c[i,j]表示该集合的大小。
核心内容: 对问题的建模,采用该模型分析既可以使用这种DP解决,也可以类似LIS问题的DP解决,还可以
贪心解决。但是所有的这些都建立在正确的建立了数学模型的基础之上。
LIS DP方法: C[j]表示集合s(0, j)的最大兼容子集大小,C[j] = max({1<=k<j, C[k]} + 1)
递归式的来由: 如果aj兼容于ak,则凡是与ak兼容的子集s(0, k)必然与aj兼容
-- 由于集合已经按照起始时间排序。所以可以采用LIS方式DP
贪心方法: 由第一种DP实现方式推得。k的选择直接采用贪心方法取集合s(i, j)中最靠前的元素。
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
namespace {
using namespace std;
typedef struct ACTIVITY
{
int s, f;
}ACTIVITY_S;
int comp(const void *op1, const void *op2)
{
ACTIVITY_S *a1 = (ACTIVITY_S *)op1;
ACTIVITY_S *a2 = (ACTIVITY_S *)op2;
if (a1->s < a2->s) return -1;
if (a1->s == a2->s) return 0;
if (a1->s > a2->s) return 1;
}
const int ACTIVITY_NUM_MAX = 32;
ACTIVITY_S activities[ACTIVITY_NUM_MAX+2];
const int ACTIVITY_TIME_MAX = 100;
int c[ACTIVITY_NUM_MAX+1][ACTIVITY_NUM_MAX+2]; // 默认初始化为0
int activity_num;
int activity_select_dp()
{
qsort(&activities[1], activity_num, sizeof(activities[0]), comp);
activities[0].f = 0; activities[activity_num+1].s = ACTIVITY_TIME_MAX; // 起始和结尾添加的辅助活动
for (int i=activity_num; i>=0; i--)
{
for (int j=i+1; j<=activity_num+1; j++ ) // s(i, i)等于空集
{
for (int k=i+1; k<j; k++)
{
if (activities[i].f<=activities[k].s && activities[k].f<=activities[j].s) // s(i, j)不为空
{
c[i][j] = max(c[i][j], c[i][k]+1+c[k][j]);
}
}
}
}
return c[0][activity_num+1];
}
}
int main()
{
cin >> activity_num;
for (int i=1; i<=activity_num; i++)
{
cin >> activities[i].s >> activities[i].f;
}
cout << activity_select_dp() << endl;
return 0;
}
活动选择问题的动态规划解
最新推荐文章于 2022-12-04 08:03:00 发布