经典DP问题系列之四:求解活动安排问题

【问题描述】
计算订单上所有活动占用时间的最大值
【输入】
第一行整数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
#include
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;
}

运行结果:
经典DP问题系列之四:求解活动安排问题_第1张图片

你可能感兴趣的:(DP,数据结构与算法,算法)