动态规划——常见动态规划模型
Posted iwillenter-top1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划——常见动态规划模型相关的知识,希望对你有一定的参考价值。
(1.)数字三角形
每次可以往右下或者左下走一格,求路径的最大权值.
(d(i,j)=max(d(i+1,j),d(i+1,j+1))+a(i,j).)边界是(d(n+1,j)=0),从下往上推(因为要保证(i+1)行在第(i)行之前更新)
for(int i=1;i<=n+1;++i) d[n+1][i]=0;
for(int i=n;i>=1;--i)
{
for(int j=1;j<=i;++j)
{
d[i][j]=max(d[i+1][j],d[i+1][j+1])+a[i][j];
}
}
(2.)嵌套矩形
有(n)个矩形,每个矩形用一个二元组((a,b))表示。我们规定矩形(X(a,b))可以嵌套在矩形(Y(c,d))中当且仅当(a<c,b<d),或者(b<c,a<d)(旋转了(90)度)。选出尽量多的矩形排成一行 ,使得除了最后一个之外,每个矩形都能嵌套在下一个矩形内。若有多解,保证字典序尽量小
(DAG)最长路问题
//dp[i]表示的是从i点出发的最长路
int dp(int x)
{
int &ans=d[x];
if(ans) return ans;
for(int i=1;i<=n;++i)
{
if(G[x][i])
{
ans=max(ans,dp(i)+1);//注意记录的是从终点到起点的距离,这是为了方便字典序最小方案的输出
}
}
d[x]=ans;
return ans;
}
void print(int i)
{
printf("%d ",i);
for(int j=1;j<=n;++j)
{
if(G[i][j]&&d[j]+1==d[i])
{
print(j);
}
}
}
for(int i=1;i<=n;++i)
{
scanf("%d%d",&a[i],&b[i]);
if(a[i]>b[i]) swap(a[i],b[i]);
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
if(a[i]>a[j]&b[i]>b[j])
{
G[j][i]=1;
}
}
}
int Max=0;
int endpos;
for(int i=1;i<=n;++i)
{
if(dp(i)>Max)
{
Max=dp[i];
endpos=i;
}
}
print(endpos);
(3.)硬币问题
[f(i)=min(inf,f[i-Vi]+1|Vi<=i), g(i)=max(-inf,g[i-Vi]+1|Vi<=i) (Vi为硬币的面值)]
(4.01)背包 已有专门专题详细讲解
(5.)点集配对问题(状压(dp))
(d(S)) 表示集合(S)配对之后的最短距离
double dis(int i,int j)
{
return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;++i) scanf("%d%d",&a[i].x,&a[i].y);
memset(d,0x7f,sizeof(d));
d[0]=0;
for(int i=1;i<(1<<n);++i)//由于第一个点无论如何都是要配对的,所以无需枚举(否则时间复杂度会
{ //乘上一个n)
int k=0;
while(!(i&(1<<k))) ++k;
for(int j=k+1;j<n;++j)
{
if(i&(1<<j)) d[i]=min(d[i],d[i^(1<<k)^(1<<j)]+dis(k,j));
}
}
}
(6.)最长上升子序列问题((LIS))
初级:(O(n^2)) (不过太不优秀了,我学会了第二种,就从没用过它)
进阶:(O(nlogn)) (d[i])表示以(a[i])结尾的最长上升子序列的长度
for(int i=1;i<=n;+i) g[i]=inf;
for(int i=0;i<n;++i)
{
int k=lower_bound(g+1,g+n+1,a[i])-g;
d[i]=k;
g[k]=a[i];
}
(7.)最长公共子序列问题((LCS))[ 注意:(LCS)有时也指最长公共后缀,与(LCP)最长公共前缀对应 ]
for(int i=0;i<la;++i)
{
for(int j=0;j<lb;++j)
{
if(a[i]==b[j])
{
d[i][j]=max(d[i][j],d[i-1][j-1]+1);
}
else if(a[i]!=b[j])
{
d[i][j]=max(d[i-1][j],d[i][j-1]);
}
}
}
还可以滚动数组优化
int f=0;
for(int i=0;i<la;++i)
{
f^=1;
for(int j=0;j<lb;++j)
{
if(a[i]==b[j])
{
d[f][j]=max(d[f][j],[f^1][j-1]+1);
}
else if(a[i]!=b[j])
{
d[f][j]=max(d[f^1][j],d[f][j-1]);
}
}
}
(8.)最大连续和
前缀和做法:
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
int Maxn=sum[n],Max=0;
for(int i=n-1;i>=1;--i)
{
Max=max(Max,Maxn-sum[i]);
Maxn=max(Maxn,sum[i]);
}
动态规划做法:(d[i])表示以i结尾的最大连续和
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i)
{
d[i]=max(0,d[i-1])+a[i];
}
以上是关于动态规划——常见动态规划模型的主要内容,如果未能解决你的问题,请参考以下文章