线性DP+树形DP

Posted huaruoji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性DP+树形DP相关的知识,希望对你有一定的参考价值。

线性DP

最长上升子序列

O(n^2)的基础算法

方程:f[i]=max(f[j]+1) j∈i+1~n

ps:每个位置的初始长度都是1!!!!

//最长上升序列 
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;
int n,a[5005],f[5005];

int main()
{
	ios::sync_with_stdio(false);
	
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		f[i]=1;
	}
//	f[n]=1;每个位置都是1 
	for(int i=n-1;i>=1;i--)
	{
		for(int j=i+1;j<=n;j++)
		{
			if(a[i]<a[j])
				f[i]=max(f[i],f[j]+1);
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=max(ans,f[i]);
	}
	cout<<ans; 

	return 0; 
}

  

最长公共子序列(LCS)

给定一个序列X=<x1,x2,x3,x4...,xm>,另一个序列Z=<z1,z2,z3,z4...,zk>,若存在一个严格递增的X的下标序列<i1,i2,i3,...,ik>对所有的1,2,3,...,k,都满足x(ik)=zk,则称Z是X的子序列

 

比如Z=<B,C,D,B>是X=<A,B,C,B,D,A,B>的子序列

方程:f(i,j)={f[i-1,j-1](a[i]=a[j]),max(f[i-1][j],f[i][j-1])(a[i]≠a[j]}

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;
char a[205],b[205];
int f[205][205]; 

int main()
{
//	ios::sync_with_stdio(false);

	scanf("%s",a+1);
	scanf("%s",b+1);
	strlen()
	int lena=strlen(a+1),lenb=strlen(b+1);//从下标1开始计算长度 size t cdecl strlen (const char  Str)
	for(int i=1;i<=lena;i++)
	{
		for(int j=1;j<=lenb;j++)
		{
			if(a[i]==b[j])
				f[i][j]=f[i-1][j-1]+1;
			else
				f[i][j]=max(f[i-1][j],f[i][j-1]);
		}
	}
	cout<<f[lena][lenb];

	return 0;
}

  

最经典的是这个图

技术图片

 

 

树形DP

战略游戏

题目描述

Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。

他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路。

注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。

请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵。

输入格式

输入数据表示一棵树,描述如下:

第一行 N,表示树中结点的数目。

第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连)。

接下来k个数,分别是每条边的另一个结点标号r1,r2,...,rk。

对于一个n(0<n≤1500)个结点的树,结点标号在0到n-1之间,在输入数据中每条边只出现一次。

输出格式

输出文件仅包含一个数,为所求的最少的士兵数目。

输入输出样例

输入 #1
4
0 1 1
1 2 2 3
2 0
3 0
输出 #1
1
输入 #2
5
3 3 1 4 2
1 1 0
2 0
0 0
4 0
输出 #2
2

说明/提示

【样例说明】

技术图片

样例1的答案是只需要1个士兵,把他布置在结点1处。

样例2的答案是需要2个士兵,把他布置在结点3处和节点1(或0)处。

 

//最长上升序列 #include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>
using namespace std;int n,a[5005],f[5005];
int main(){ios::sync_with_stdio(false);cin>>n;for(int i=1;i<=n;i++){cin>>a[i];f[i]=1;}//f[n]=1;每个位置都是1 for(int i=n-1;i>=1;i--){for(int j=i+1;j<=n;j++){if(a[i]<a[j])f[i]=max(f[i],f[j]+1);}}int ans=0;for(int i=1;i<=n;i++){ans=max(ans,f[i]);}cout<<ans; 
return 0; }

 

以上是关于线性DP+树形DP的主要内容,如果未能解决你的问题,请参考以下文章

线性DP+树形DP

[提升性选讲] 树形DP进阶:一类非线性的树形DP问题(例题 BZOJ4403 BZOJ3167)

树形 DP 总结

树形 DP 总结

ACM - 动态规划小白入门:背包 / 线性 / 区间 / 计数 / 数位统计 / 状压 / 树形 / 记忆化 DP

树形DP小结