【问题描述】
计算订单上所有活动占用时间的最大值
【输入】
第一行整数n表示订单上活动的总个数
接着的n行每一行中包括两个整数p和k, 分别代表每个活动开始的时间和结束的时间
【输出】
输出所有活动占用时间的最大值
【输入样例】
11
1 4
0 6
3 5
3 8
5 7
5 9
6 10
8 11
8 12
2 13
12 15
【输出样例】
13
【思路】
这个问题我第一次见到是在学贪心算法时,这个问题还可以直接深搜dfs,状态变量k表示当前的活动序号,一开始有n种选择,所以dfs思路也出来了。做这一道题,我们一般要先对这组数据按照结束时间从小到大排一个序。
本题我们用dp求解,设dp[i]为前i个活动能占用的最大时间的值,那么我们在手写dp数表的时候可以发现,dp[i]取决于所有结束时间小于i的活动k的dp值,写做状态转移方程即:dp[i] = max(dp[k]) + a[i].end - a[i].start(0 <= k < i && a[k].end <= a[i].start)
状态转移方程在手写dp数表的时候其实就很容易发现了,感觉就和最大子序列和有点相似
参考代码:
/*
动态规划
11
1 4
0 6
3 5
3 8
5 7
5 9
6 10
8 11
8 12
2 13
12 15
*/
#include<iostream>
#include<algorithm>
using namespace std;
struct Act{
int start;
int end;
};
const int maxn = 100;
Act a[maxn];
int dp[maxn]; //dp[i]为前i个活动能获得的最长活动时间
int n;
bool cmp(Act x, Act y)
{
return x.end < y.end ? true : false;
}
int DP()
{
//边界
dp[0] = a[0].end - a[0].start;
//else
for(int i = 1;i < n;i++)
{
int max_res = a[i].end - a[i].start;
for(int j = 0;j < i;j++)
{
if(a[j].end <= a[i].start && dp[j] + a[i].end - a[i].start > max_res)
max_res = dp[j] + a[i].end - a[i].start;
}
dp[i] = max_res;
}
//打印dp数组
cout << "dp数组为:";
for(int i = 0;i < n;i++)
{
cout << dp[i] << " ";
}
cout << endl;
//找最大的
int max_r = 0;
for(int i = 0;i < n;i++)
{
if(dp[i] > max_r)
max_r = dp[i];
}
return max_r;
}
int main()
{
cin >> n;
for(int i = 0;i < n;i++)
{
cin >> a[i].start >> a[i].end;
}
sort(a, a + n, cmp); //按结束时间来排序
cout << "能获得的最长活动时间是:" << DP() << endl;
return 0;
}
运行结果: