DP有关模板
2018-02-07 18:31
183 查看
三角塔式:
The Triangle
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int n;
int maxSum[MAX][MAX];
int MaxSum(int i, int j){
if( maxSum[i][j] != -1 )
return maxSum[i][j];
if(i==n)
maxSum[i][j] = D[i][j];
else{
int x = MaxSum(i+1,j);
int y = MaxSum(i+1,j+1);
maxSum[i][j] = max(x,y)+ D[i][j];
}
return maxSum[i][j];
}
int main(){
int i,j;
cin >> n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++) {
cin >> D[i][j];
maxSum[i][j] = -1;
}
cout << MaxSum(1,1) << endl;
} 最长字段和:
Max Sum
最大m子段和:
Max Sum Plus Plus
最长上升子序:
Constructing Roads In JGShining's Kingdom
#include<cstdio>
#include<algorithm>
const int MAXN=200001;
int a[MAXN];
int d[MAXN];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
d[1]=a[1];
int len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>d[len])
d[++len]=a[i];
else
{
int j=std::lower_bound(d+1,d+len+1,a[i])-d;
d[j]=a[i];
}
}
printf("%d\n",len);
return 0;
}Common Subsequence
背包问题——(本文作者frankchenfu,blogs网址http://www.cnblogs.com/frankchenfu/,转载请保留此文字。)
1.01背包:有n种物品与承重为m的背包。每种物品只有一件,每个物品都有对应的重量weight[i]与价值value[i],求解如何装包使得价值最大。
2.完全背包:有n种物品与承重为m的背包。每种物品有无限多件,每个物品都有对应的重量weight[i]与价值value[i],求解如何装包使得价值最大。
3.多重背包:有n种物品与承重为m的背包。每种物品有有限件num[i],每个物品都有对应的重量weight[i]与价值value[i],求解如何装包使得价值最大。
1.01背包
①、确认子问题和状态
01背包问题需要求解的就是,为了体积V的背包中物体总价值最大化,N件物品中第i件应该放入背包中吗?(其中每个物品最多只能放一件)
为此,我们定义一个二维数组,其中每个元素代表一个状态,即前i个物体中若干个放入体积为V背包中最大价值。数组为:f[N][V],其中fij表示前i件中若干个物品放入体积为j的背包中的最大价值。
②、初始状态
初始状态为f[0][0-V]和f[0-n][0]都为0.
前者表示前0个物品(也就是空物品)无论装入多大的包中总价值都为0,后者表示体积为0的背包啥价值的物品都装不进去。
③、转移函数
if (背包体积j小于物品i的体积)
f[i][j] = f[i-1][j] //背包装不下第i个物体,目前只能靠前i-1个物体装包
else
f[i][j] = max(f[i-1][j], f[i-1][j-Vi] + Wi)
(1). j < w[i] 的情况,这时候背包容量不足以放下第 i 件物品,只能选择不拿
m[ i ][ j ] = m[ i-1 ][ j ]
(2). j>=w[i] 的情况,这时背包容量可以放下第 i 件物品,我们就要考虑拿这件物品是否能获取更大的价值。
如果拿取,m[ i ][ j ]=m[ i-1 ][ j-w[ i ] ] + v[ i ]。 这里的m[ i-1 ][ j-w[ i ] ]指的就是考虑了i-1件物品,背包容量为j-w[i]时的最大价值,也是相当于为第i件物品腾出了w[i]的空间。
如果不拿,m[ i ][ j ] = m[ i-1 ][ j ] , 同(1)
究竟是拿还是不拿,自然是比较这两种情况那种价值最大。
/*
01背包
适用于输入格式如下的问题,出现问题请自行调整:
第一行两个整数M, N分别表示背包空间与物品总数;
第2到N+1行每行两个整数,分别表示这类物品每个的价值和所需空间。
*/
#include<cstdio>
const int MAXM=10001,MAXN=51;
int m,n;
int w[MAXN],c[MAXN];
int f[MAXM];
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]);
for(int i=1;i<=n;i++)
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+c[i]);
printf("%d\n",f[m]);
return 0;
}2.完全背包
完全背包和01背包类似,只不过每种物品有无限多件,仅仅是for循环的顺序从逆序变成了顺序。
/*
完全背包,输入规则:
第一行两个整数M, N分别表示背包空间与物品总数;
第2到N+1行每行两个整数,分别表示这类物品每个的价值和所需空间。
*/
#include<cstdio>
const int MAXM=10001,MAXN=51;
int m,n;
int w[MAXN],c[MAXN];
int f[MAXM];
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]);
for(int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
printf("%d\n",f[m]);
return 0;
}
3.多重背包
首先这种可以把物品拆开,把相同的num[i]件物品 看成 价值跟重量相同的num[i]件不同的物品,就转化成了一个规模稍微大一点的01背包了。
/*
多重背包,输入格式:
第一行,一个整数n,物品数量;
第二行,n个整数,第i个整数表示第i个物品的价格bi;
第三行,n个整数,第i个整数表示第i个物品的数量ci;
第四行,一个整数m,背包空间。
*/
#include<cstdio>
const int MAXM=10001,MAXN=6001;
int v[MAXM],w[MAXM];
int f[MAXN];
int n,m,p;
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x,y,s,t=1;
scanf("%d%d%d",&x,&y,&s);
for(;s>=t;t<<=1)//二进制思想
{
v[++p]=x*t;
w[p]=y*t;
s-=t;
}
v[++p]=x*s;
w[p]=y*s;
}
for(int i=1;i<=p;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
printf("%d\n",f[m]);
return 0;
}
The Triangle
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int n;
int maxSum[MAX][MAX];
int MaxSum(int i, int j){
if( maxSum[i][j] != -1 )
return maxSum[i][j];
if(i==n)
maxSum[i][j] = D[i][j];
else{
int x = MaxSum(i+1,j);
int y = MaxSum(i+1,j+1);
maxSum[i][j] = max(x,y)+ D[i][j];
}
return maxSum[i][j];
}
int main(){
int i,j;
cin >> n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++) {
cin >> D[i][j];
maxSum[i][j] = -1;
}
cout << MaxSum(1,1) << endl;
} 最长字段和:
Max Sum
#include<string.h> #include<stdio.h> int main() { int t,n,a[100005]; int T=0; while(scanf("%d",&t)!=-1) while(t--) { T++; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int head=1,tail=1,x=1; int max=a[1],sum=a[1]; for(int i=2;i<=n;i++) { if(sum+a[i]<a[i]) { x=i; sum=a[i]; } else { sum+=a[i]; } if(sum>max) { max=sum; tail=i; head=x; } } printf("Case %d:\n%d %d %d\n",T,max,head,tail); if(t) printf("\n"); } return 0; }
最大m子段和:
Max Sum Plus Plus
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define N 1000000 #define INF 0x7fffffff int a[N+10]; int dp[N+10],Max[N+10];//max( dp[i-1][k] ) 就是上一组 0....j-1 的最大值。 int main() { int n,m,mmax; while (~scanf("%d%d",&m,&n)) { for (int i=1;i<=n;i++) { scanf("%d",&a[i]); } memset(dp,0,sizeof(dp)); memset(Max,0,sizeof(Max)); for (int i=1;i<=m;i++)//分成几组 { mmax=-INF; for (int j=i;j<=n;j++)//j个数分成i组,至少要有i个数 { dp[j]=max(dp[j-1]+a[j],Max[j-1]+a[j]); Max[j-1]=mmax; mmax=max(mmax,dp[j]); } } printf ("%d\n",mmax); } return 0; }
最长上升子序:
Constructing Roads In JGShining's Kingdom
#include<cstdio>
#include<algorithm>
const int MAXN=200001;
int a[MAXN];
int d[MAXN];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
d[1]=a[1];
int len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>d[len])
d[++len]=a[i];
else
{
int j=std::lower_bound(d+1,d+len+1,a[i])-d;
d[j]=a[i];
}
}
printf("%d\n",len);
return 0;
}Common Subsequence
#include<bits/stdc++.h> using namespace std; char a[505],b[505]; int dp[505][505]; int main() { while(~scanf("%s%s",a,b)) { int len1=strlen(a); int len2=strlen(b); for(int i=0;i<len1;i++) dp[0][i]=0; for(int i=0;i<len2;i++) dp[i][0]=0; for(int i=1;i<=len1;i++) { for(int j=1;j<=len2;j++) { if(a[i-1]==b[j-1]) dp[i][j]=dp[i-1][j-1]+1; else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); d65a } } printf("%d\n",dp[len1][len2]); } }
背包问题——(本文作者frankchenfu,blogs网址http://www.cnblogs.com/frankchenfu/,转载请保留此文字。)
1.01背包:有n种物品与承重为m的背包。每种物品只有一件,每个物品都有对应的重量weight[i]与价值value[i],求解如何装包使得价值最大。
2.完全背包:有n种物品与承重为m的背包。每种物品有无限多件,每个物品都有对应的重量weight[i]与价值value[i],求解如何装包使得价值最大。
3.多重背包:有n种物品与承重为m的背包。每种物品有有限件num[i],每个物品都有对应的重量weight[i]与价值value[i],求解如何装包使得价值最大。
1.01背包
①、确认子问题和状态
01背包问题需要求解的就是,为了体积V的背包中物体总价值最大化,N件物品中第i件应该放入背包中吗?(其中每个物品最多只能放一件)
为此,我们定义一个二维数组,其中每个元素代表一个状态,即前i个物体中若干个放入体积为V背包中最大价值。数组为:f[N][V],其中fij表示前i件中若干个物品放入体积为j的背包中的最大价值。
②、初始状态
初始状态为f[0][0-V]和f[0-n][0]都为0.
前者表示前0个物品(也就是空物品)无论装入多大的包中总价值都为0,后者表示体积为0的背包啥价值的物品都装不进去。
③、转移函数
if (背包体积j小于物品i的体积)
f[i][j] = f[i-1][j] //背包装不下第i个物体,目前只能靠前i-1个物体装包
else
f[i][j] = max(f[i-1][j], f[i-1][j-Vi] + Wi)
(1). j < w[i] 的情况,这时候背包容量不足以放下第 i 件物品,只能选择不拿
m[ i ][ j ] = m[ i-1 ][ j ]
(2). j>=w[i] 的情况,这时背包容量可以放下第 i 件物品,我们就要考虑拿这件物品是否能获取更大的价值。
如果拿取,m[ i ][ j ]=m[ i-1 ][ j-w[ i ] ] + v[ i ]。 这里的m[ i-1 ][ j-w[ i ] ]指的就是考虑了i-1件物品,背包容量为j-w[i]时的最大价值,也是相当于为第i件物品腾出了w[i]的空间。
如果不拿,m[ i ][ j ] = m[ i-1 ][ j ] , 同(1)
究竟是拿还是不拿,自然是比较这两种情况那种价值最大。
/*
01背包
适用于输入格式如下的问题,出现问题请自行调整:
第一行两个整数M, N分别表示背包空间与物品总数;
第2到N+1行每行两个整数,分别表示这类物品每个的价值和所需空间。
*/
#include<cstdio>
const int MAXM=10001,MAXN=51;
int m,n;
int w[MAXN],c[MAXN];
int f[MAXM];
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]);
for(int i=1;i<=n;i++)
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+c[i]);
printf("%d\n",f[m]);
return 0;
}2.完全背包
完全背包和01背包类似,只不过每种物品有无限多件,仅仅是for循环的顺序从逆序变成了顺序。
/*
完全背包,输入规则:
第一行两个整数M, N分别表示背包空间与物品总数;
第2到N+1行每行两个整数,分别表示这类物品每个的价值和所需空间。
*/
#include<cstdio>
const int MAXM=10001,MAXN=51;
int m,n;
int w[MAXN],c[MAXN];
int f[MAXM];
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]);
for(int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
printf("%d\n",f[m]);
return 0;
}
3.多重背包
首先这种可以把物品拆开,把相同的num[i]件物品 看成 价值跟重量相同的num[i]件不同的物品,就转化成了一个规模稍微大一点的01背包了。
/*
多重背包,输入格式:
第一行,一个整数n,物品数量;
第二行,n个整数,第i个整数表示第i个物品的价格bi;
第三行,n个整数,第i个整数表示第i个物品的数量ci;
第四行,一个整数m,背包空间。
*/
#include<cstdio>
const int MAXM=10001,MAXN=6001;
int v[MAXM],w[MAXM];
int f[MAXN];
int n,m,p;
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x,y,s,t=1;
scanf("%d%d%d",&x,&y,&s);
for(;s>=t;t<<=1)//二进制思想
{
v[++p]=x*t;
w[p]=y*t;
s-=t;
}
v[++p]=x*s;
w[p]=y*s;
}
for(int i=1;i<=p;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
printf("%d\n",f[m]);
return 0;
}
#include<bits/stdc++.h> using namespace std; int dp[1005]; int weight[1005],value[1005],num[1005]; int main() { int n,m; cin>>n>>m; memset(dp,0,sizeof(dp)); for(int i=1; i<=n; i++) cin>>weight[i]>>value[i]>>num[i]; for(int i=1; i<=n; i++)//每种物品 for(int k=0; k<num[i]; k++)//其实就是把这类物品展开,调用num[i]次01背包代码 for(int j=m; j>=weight[i]; j--)//正常的01背包代码 dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); cout<<dp[m]<<endl; return 0; }
相关文章推荐
- HDU 3555 Bomb(数位DP模板啊两种形式)
- 与13有关(数位dp)
- codeforces 182E Wooden Fence(方案数DP)【模板】
- 【记忆化搜索】滑雪(dp模板)
- 数位DP模板(感觉好神奇) 看大神的 不是自己写的
- HDU 3555 Bomb(数位DP模板啊两种形式)
- 有关矩阵的模板【模板】
- C++——数位DP模板——Windy数【四川省选2009】
- 【newcoder 】数圈圈 【数位DP 模板】
- 有关删除数字的dp问题
- 挑战程序设计竞赛2.3.3 有关计数问题的DP 多重集组合数
- 有关动态规划(主要是数位DP)的一点讨论
- 与PHP开发有关的模板问题
- 数位dp模板
- hdu 2089(数位DP模板题)
- 算法模板——数位dp
- 数位DP模板
- 【无聊放个模板系列】HDU 3506 (四边形不等式优化DP-经典石子合并问题[环形])
- E - Strategic Game (HDU - 1054 )(最小顶点覆盖)(匈牙利算法模板)(树形DP)
- codeforces 5C Longest Regular Bracket Sequence(dp+技巧)【最长连续括号模板】