动态规划之树形DP,区间DP

树形DP

树形 DP,即在树上进行的 DP。由于树固有的递归性质,树形 DP 一般都是递归进行的。

以下面这道题为例,介绍一下树形 DP 的一般过程。
https://www.luogu.org/problemnew/show/P1352
动态规划之树形DP,区间DP_第1张图片
我们可以定义 dp[i][0/1] 代表以 i 为根的子树的最优解(第二维的值为 0 代表 i 不参加舞会的情况,1 代表 i 参加舞会的情况)。

显然,我们可以推出下面两个状态转移方程(其中下面的 x 都是 i 的儿子):

dp[i][0] += max{dp[x][1],dp[x][0])(上司不参加舞会时,下属可以参加,也可以不参加)
dp[i][1] += dp[x][0](上司参加舞会时,下属都不会参加)
这里我们定义一个son的vector数组,来存储职员之间的关系,其中第一维存储的是上司,第二维大小是可变的,存储其对应的下属。h[i]表示职员 i 快乐值,v[i[表示职员 i 是否有上司。
代码如下:

//树状DP 
#include
# define LOCAL
using namespace std;
const int maxn = 6005;
int h[maxn],v[maxn];//h数组存储快乐值,v数组存储是否有boss 
int dp[maxn][2];
vector son[maxn];
void solve(int x){
	dp[x][0] = 0;
	dp[x][1] = h[x];
	for(int i=0;i> n;
	for(int i=1;i<=n;i++)
		cin >> h[i];
	for(int i=1;i<=n;i++){
		int x,y;
		cin >> x >> y;	//输入的数据最小为1 
		if(!x && !y)
			break;
		son[y].push_back(x);
		v[x] = 1;
	}
	int root;
	for(int i=1;i<=n;i++)
		if(!v[i]){
			root = i;
			break;
		}
	solve(root);
	cout << max(dp[root][0],dp[root][1]) << endl;
	return 0;
}

区间DP

动态规划之树形DP,区间DP_第2张图片
模板: 阶段 ····> 状态 ····> 决策(从外到内)
动态规划之树形DP,区间DP_第3张图片

//石子合并
#include
# define LOCAL
const int inf = 0x3f3f3f;
const int maxn = 205; 
using namespace std;
int a[maxn];//堆石子数 
int sum[maxn];//计算某区间内得分 
int dpmin[maxn][maxn],dpmax[maxn][maxn];//区间DP
void deal(int x){
	memset(sum,0,sizeof(sum));
	memset(dpmin,inf,sizeof(dpmin));
	memset(dpmax,-inf,sizeof(dpmax));
	for(int i=1;i<=x*2;i++){
		dpmin[i][i] = 0;
		dpmax[i][i] = 0;
		sum[i] = sum[i-1] + a[i];
	//	cout << sum[i] << "\n";
	}
}
void solve(int x){
	for(int len=2;len<=x;len++)//阶段 
		for(int l=1;l<=2*x-len+1;l++){//状态:左端点 
			int r = len + l - 1;//状态:右端点 
			for(int k=l;k> n){
		for(int i=1;i<=n;i++){
			cin >> a[i];
			a[i+n] = a[i];
			}
		deal(n);
		solve(n);
		cout << inf;
	}
	return 0;
}

注意是环状的,需要和线性的区分:

memset(dp,0x3f3f3f3f,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){
    dp[i][i] = 0;
    sum[i] = sum[i-1] + a[i];
}
for(int len=2;len<=n;len++)
   for(int l=1;l<=n-len+1;l++){
        int r = l+len-1;
        for(int k=l;j

在数据处理上,环状DP需要处理大于n(元素个数)的元素,使得构成一个环。
线性的dp数组每一个元素是只会进行一次比较赋值;
环状的dp数组的大于n(元素个数)元素是会进行第二次比较,根据要求取最小或是最大。

你可能感兴趣的:(C++,动态规划,树形DP,区间DP)