acm第九次区间dp+多重背包做题总结

一、区间dp
1、所谓 区间DP主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值。
2、基本分析步骤:
①描述状态。
②状态转移方程。
③递推边界。
3、一般代码实现
//mst(dp,0) 初始化DP数组
for(int i=1;i<=n;i++)
{
dp[i][i]=初始值
}
for(int len=2;len<=n;len++) //区间长度
for(int i=1;i<=n;i++) //枚举起点
{
int j=i+len-1; //区间终点
if(j>n) break; //越界结束
for(int k=i;k<j;k++) //枚举分割点,构造状态转移方程
{
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
}
}
4、以上只是理论,我做题是依旧困难重重,感觉还是做题太少,一些题知道要用区间dp来写,但却写不出来,有思路了写的也是来会改好多遍,建议多做点题。
二、多重背包自己做题总结方法
多重背包求解
1 多重背包一般解法,一维数组,3从循环(ijk),i件物品,j的容量(从大到小),k的个数
设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程 :
f[j]=max{f[j],f[j−k∗w[i]]+k∗v[i]}
例:
// 多重背包:一维法
for (int i = 1; i <= n; i++)
for (int j = W; j >= w[i]; j–)
for (int k = 0; k <= num[i]; k++) {
if (j - k * w[i] >= 0 )
f[j] = max(f[j],f[j - k * w[i]] + k * v[i]);
}

	return f[W]; // 最优解
}

2、多重背包转换为01背包
共有m个物品,每个物品有c件,价格为a,重量为b,总容量为n,这是多重背包问题
转换:
共有l件物品,每个物品一件(只不过有c1件物品一模一样(价钱和重量一样),c2件一模一样,c3件…cm件),价格为a,重量为b,总容量为n,这是01背包问题
l=m*c
int main ()
{
int t,n,m,a,b,c,l;
int i,j;
cin>>t;
while(t–)
{
l=0;
cin>>n>>m;//n为总容量,m为m个物品
memset(v,0,sizeof(v));
memset(p,0,sizeof§);
for(i=0;i<m;i++)
{
cin>>a>>b>>c;//a价格、b重量、c个数
while(c–) //转换为01背包
{
v[l]=a;
p[l]=b;
l++;
}//每个物品都只有一个,从m变为l个物品
}//每个物品只有一个,v表示钱,p表示重量
memset(dp,0,sizeof(dp));
for(i=0;i<l;i++)//注意:i小于l不是m
for(j=n;j>=v[i];j–)//01背包从大到小
dp[j]=max(dp[j],dp[j-v[i]]+p[i]);//一维01背包
cout<<dp[n]<<endl;
}
return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43550247/article/details/89058825