三角塔式:
#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;
}
最长字段和:
#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子段和:
#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;
}
#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]);
}
}
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;
}