1.初步动态规划:
①:数字三角形问题:
有形如下图所示的数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一起走到底层,要求找出一条路径,使路径上的值最大。
样例输入:
5
13
11 8
12 7 26
6 14 15 8
12 7 13 24 11
样例输出:
86(13->8->26->15->24)
分析:因为从上面往下走,必须要知道左右两边那条路更大。所以要从底层开始层层递进,直至找到所标记的点。
dp[i][j] = max(dp[i+1][j],dp[i+1][j+1])+a[i][j];
#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 10000
int a[maxn][maxn];
int dp[maxn][maxn];
using namespace std;
int main()
{
int n;
scanf("%d",&n);
for(int i = 0; i < n; i ++)
for(int j = 0; j <= i; j++)
scanf("%d",&a[i][j]);
for(int i = 0; i < n; i ++)
dp[n-1][i] = a[n-1][i];
for(int i = n-2; i >= 0; i--)
for(int j = 0;j <= i; j ++)
dp[i][j] = max(dp[i+1][j],dp[i+1][j+1]) + a[i][j];
printf("%d\n",dp[0][0]);
return 0;
}
2.序列dp
1)最长上升子序列LIS
输入n及一个长度为n的数列,求出此序列的最长上升子序列长度。上升子序列指的是对于任意的i<j都满足ai<aj的子序列。(1<=n<=1000,0<=ai<=1000000)
样例输入:
5
4 2 3 1 5
样例输出:
3(最长上升子序列为2, 3, 5)
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 1005
int a[maxn];
int dp[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i ++)
{
scanf("%d",&a[i]);
dp[i] = 1;
}
int ans = 1;
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j < i; j ++)
{
if(a[j]<a[i])
dp[i] = max(dp[i],dp[j]+1);
}
ans = max(ans,dp[i]);
}
printf("%d\n",ans);
return 0;
}
3.字符串的最长公共子序列和最大公共子串
区别:
例如:acdea
acddda
最长公共子序列为4(“acda”)
最大公共子串为3(“acd”)
1>.最长公共子序列
动态方程:dp[i+1][j+1] = dp[i][j] + 1;
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1005
int dp[maxn][maxn];
int main()
{
char s1[maxn],s2[maxn];
while(~scanf("%s",s1))
{
scanf("%s",s2);
int len1 = strlen(s1);
int len2 = strlen(s2);
memset(dp,0,sizeof(dp));
for(int i = 0; i < len1; i ++)
for(int j = 0; j < len2; j ++)
{
if(s1[i]==s2[j])
dp[i+1][j+1] = dp[i][j] + 1;
else
dp[i+1][j+1] = max(dp[i+1][j],dp[i][j+1]);
}
printf("%d\n",dp[len1][len2]);
}
}
2>最大公共子序列
在情况1的基础上稍加改动
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1005
int dp[maxn][maxn];
int main()
{
char s1[maxn],s2[maxn];
while(~scanf("%s",s1))
{
scanf("%s",s2);
int len1 = strlen(s1);
int len2 = strlen(s2);
memset(dp,0,sizeof(dp));
int ans = 0;
for(int i = 0; i < len1; i ++)
for(int j = 0; j < len2; j ++)
{
if(s1[i]==s2[j])
dp[i+1][j+1] = dp[i][j] + 1;
else
dp[i+1][j+1] = max(dp[i+1][j],dp[i][j+1]);
ans = max(ans,dp[i+1][j+1]);
}
printf("%d\n",dp[len1][len2]);
}
}
2.背包问题:
1>01背包 有n件物品,背包总量为m,给出n种物品的价格和重量,求出最优解。
#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 5001
using namespace std;
int a[maxn],b[maxn];
int dp[maxn];
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i = 1; i <= n ; i ++)
scanf("%d %d",&a[i],&b[i]);//价值为a,重量为b
for(int i = 1; i <= n; i ++)
for(int j = m; j >= b[i] ; j--)
{
dp[j] = max(dp[j],dp[j-b[i]]+a[i]);
}
printf("%d\n",dp[m]);
}
完全背包
有N种物品和容量为M的包,其中N种物品有无数件,并给出N种物品的价值和重量。
#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 5001
using namespace std;
int a[maxn],b[maxn];
int dp[maxn];
#define INF 0x3f3f3f3f
int main()
{
int n,m;
scanf("%d %d",&n,&m);
memset(dp,INF,sizeof(dp));
for(int i = 1; i <= n ; i ++)
scanf("%d %d",&a[i],&b[i]);//价值为a,重量为b
for(int i = 1; i <= n; i ++)
for(int j = b[i]; j <= m; j ++)
{
dp[j] = max(dp[j],dp[j-b[i]]+a[i]);
}
if(dp[m]==INF)
printf("NO\n");
else
printf("%d\n",dp[m]);
}
多重背包
有一个容量为V的背包和N件物品,第i件物品最多有Num[i]件,每件物品的重量是weight[i],收益是cost[i]。
#include <iostream>
using namespace std;
const int N = 3;//物品个数
const int V = 8;//背包容量
int Weight[N + 1] = {0,1,2,2};
int Value[N + 1] = {0,6,10,20};
int Num[N + 1] = {0,10,5,2};
int f[V + 1] = {0};
void ZeroOnePack(int nWeight,int nValue)
{
for (int v = V;v >= nWeight;v--)
{
f[v] = max(f[v],f[v - nWeight] + nValue);
}
}
void CompletePack(int nWeight,int nValue)
{
for (int v = nWeight;v <= V;v++)
{
f[v] = max(f[v],f[v - nWeight] + nValue);
}
}
int MultiKnapsack()
{
int k = 1;
int nCount = 0;
for (int i = 1;i <= N;i++)
{
if (Weight[i] * Num[i] >= V)
{
//完全背包:该类物品原则上是无限供应,
//此时满足条件Weight[i] * Num[i] >= V时,
//表示无限量供应,直到背包放不下为止.
CompletePack(Weight[i],Value[i]);
}
else
{
k = 1;
nCount = Num[i];
while(k <= nCount)
{
ZeroOnePack(k * Weight[i],k * Value[i]);
nCount -= k;
k *= 2;
}
ZeroOnePack(nCount * Weight[i],nCount * Value[i]);
}
}
return f[V];
}
int main()
{
cout<<MultiKnapsack()<<endl;
return 0
}