您的位置:首页 > 其它

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

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: