一、线性dp
一般是线性问题较简单,思路与之前背包问题一样
1,数字三角形
需要注意的是右上边那一斜的数,我们在计算他们时,会用到他们的右上,所以初始化时要多出来一个i+1;
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 510, INF = 1e9;
int n;
int a[N][N];
int f[N][N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
cin>>a[i][j];
}
}
for(int i=0;i<=n;i++)
{
for(int j=0;j<=i+1;j++)
{
f[i][j] = -INF;
}
}
f[1][1] = a[1][1];
for(int i=2;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
f[i][j] = max(f[i-1][j-1] + a[i][j], f[i-1][j] + a[i][j]);
}
}
int res = -INF;
for(int i=1;i<=n;i++)
{
if(res <= f[n][i]) res = f[n][i];
}
cout<<res<<endl;
return 0;
}
2,最长上升子序列
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int n;
int a[N], f[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
f[i] = 1;
for(int j=1;j<=i;j++)
{
if(a[j] < a[i])
f[i] = max(f[i], f[j] + 1);
}
}
int res = -1;
for(int i=1;i<=n;i++) res = max(res, f[i]);
cout<<res<<endl;
return 0;
}
3,最长公共子序列
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int n, m;
char a[N], b[N];
int f[N][N];
int main()
{
cin>>n>>m;
scanf("%s%s", a+1, b+1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
f[i][j] = max(f[i-1][j], f[i][j-1]);
if(a[i] == b[j]) f[i][j] = max(f[i][j], f[i-1][j-1] + 1);
}
}
cout<<f[n][m]<<endl;
return 0;
}
二,区间dp
石子合并
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 310;
int n;
int s[N];
int f[N][N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i];
for(int i=1;i<=n;i++) s[i] += s[i-1];
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1 <= n;i++)
{
int l = i,r = i + len - 1;
f[l][r] = 1e8;
for(int k=l;k<=r;k++)
{
f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l-1]);
}
}
}
cout<<f[1][n]<<endl;
return 0;
}