动态规划的背包问题
2018-01-28 11:57
218 查看
背包问题有许多
01背包:一种只能取一次
多重背包:一种可以取有限的次数
完全背包:一种可以取无数次
啧
最近做dp做的快吐了···
先来个简单的01背包
luogu1060 自己找题吧···
直接上代码:
luogu1164
求方案数的
也是01背包
然后再来个完全背包的吧
luogu1616
然后多重背包
luogu1077 数据范围不大暴力枚举就行
多重背包好像可以二进制拆分优化
但这道求方案数的好像不太可以
粘代码:
咳咳
这么多水题
来个难的
luogu1880石子合并
令人窒息的操作
其实就是线性dp
遇到环的问题先复制转化成线
然后倒推起点
一段一段搜
取各个段中间的值都遍历一遍
找最大值和最小值
其他的线性dp和这个思路差不多都
以及luogu1057
也是一个环的问题
不过这个问题有些不同
思路就是这个人的等于左边传过来的加上右边传过来的
注意第一个和最后一个要单独拿出来
luogu1063
依然是环的问题
和石子合并一个思路
也是一段段的推
在这提供两种写法
第一种:
以i为一段的长度,j为起点,i+j-1为终点,k为中间值
第二种:
以i为起点,j为终点,每段都是n,k为中间值
两种思想都一样
但是还是认为第二种思路更清晰
第一种比较迷容易写错
01背包:一种只能取一次
多重背包:一种可以取有限的次数
完全背包:一种可以取无数次
啧
最近做dp做的快吐了···
先来个简单的01背包
luogu1060 自己找题吧···
直接上代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,v[30],w[30],dp[26][30000],ans; int main() { cin>>n>>m; for(int i=1;i<=m;i++) { cin>>v[i]>>w[i]; } for(int i=1;i<=m;i++) for(int j=i;j<=n;j++) { if(j-v[i]>=0) dp[i][j]=max(dp[i-1][j-v[i]]+w[i]*v[i],dp[i-1][j]);//dp方程 else dp[i][j]=dp[i-1][j]; } for(int i=1;i<=m;i++) { for(int j=i;j<=n;j++) ans=max(ans,dp[i][j]); } cout<<ans<<endl; return 0; }
luogu1164
求方案数的
也是01背包
#include<iostream> #include<cstdio> #define maxn 10005 using namespace std; int n,m,a[maxn],dp[maxn],mx; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; } dp[0]=1; for(int i=1;i<=n;i++) for(int j=m;j>=a[i];j--)//注意这里要倒着推,才能保证不会重复算 { dp[j]=dp[j-a[i]]+dp[j]; } cout<<dp[m]<<endl; return 0; }
然后再来个完全背包的吧
luogu1616
#include<iostream> #include<cstdio> using namespace std; int t,m,v[10005],tim[10005],dp[100005]; int main() { cin>>t>>m; for(int i=1;i<=m;i++) { cin>>tim[i]>>v[i]; } for(int i=1;i<=t;i++)//以时间为第一重循环 { int maxn=0; for(int j=1;j<=m;j++) { if(i-tim[j]>=0) maxn=max(maxn,dp[i-tim[j]]+v[j]); else maxn=max(maxn,dp[i]);//dp方程 } dp[i]=maxn;//算出每个时间能达到的最大值 } cout<<dp[t]<<endl; return 0; }
然后多重背包
luogu1077 数据范围不大暴力枚举就行
多重背包好像可以二进制拆分优化
但这道求方案数的好像不太可以
粘代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #define maxn 105 #define md 1000007 using namespace std; int n,m,a[maxn],dp[maxn][maxn]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=0;i<=m;i++) dp[i][0]=1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=j;k>=j-a[i];k--) { if(k>=0) { dp[i][j]+=dp[i-1][k],dp[i][j]%=md; } else break; } printf("%d\n",dp [m]); return 0; }
咳咳
这么多水题
来个难的
luogu1880石子合并
令人窒息的操作
其实就是线性dp
遇到环的问题先复制转化成线
然后倒推起点
一段一段搜
取各个段中间的值都遍历一遍
找最大值和最小值
其他的线性dp和这个思路差不多都
#include<iostream> #include<cstdio> #define INF 0x7fffff using namespace std; int n,a[205],b[205],mx,mn,dps[2005][2005],dpl[2005][2005]; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];//复制 for(int i=1;i<=2*n;i++) b[i]=b[i-1]+a[i];//前缀和 for(int i=2*n-1;i>=1;i--)//倒推起点 for(int j=i+1;j<=i+n-1;j++)//长度为n的一段 { dps[i][j]=INF; for(int k=i;k<j;k++)//遍历中间值 { dps[i][j]=min(dps[i][j],dps[i][k]+dps[k+1][j]+b[j]-b[i-1]);//dp方程 dpl[i][j]=max(dpl[i][j],dpl[i][k]+dpl[k+1][j]+b[j]-b[i-1]); } } mn=INF; for(int i=1;i<=n;i++) { mx=max(mx,dpl[i][i+n-1]); mn=min(mn,dps[i][i+n-1]); } cout<<mn<<endl<<mx<<endl; return 0; }
以及luogu1057
也是一个环的问题
不过这个问题有些不同
思路就是这个人的等于左边传过来的加上右边传过来的
注意第一个和最后一个要单独拿出来
#include<iostream> #include<cstdio> using namespace std; int n,m,dp[35][35]; int main() { cin>>n>>m; dp[1][0]=1; for(int i=1;i<=m;i++) { dp[1][i]=dp[2][i-1]+dp [i-1]; dp [i]=dp[n-1][i-1]+dp[1][i-1]; for(int j=2;j<n;j++) dp[j][i]=dp[j-1][i-1]+dp[j+1][i-1]; } cout<<dp[1][m]<<endl; return 0; }
luogu1063
依然是环的问题
和石子合并一个思路
也是一段段的推
在这提供两种写法
第一种:
以i为一段的长度,j为起点,i+j-1为终点,k为中间值
第二种:
以i为起点,j为终点,每段都是n,k为中间值
两种思想都一样
但是还是认为第二种思路更清晰
第一种比较迷容易写错
#include<iostream> #include<cstdio> #define maxn 300 using namespace std; int n,a[maxn],dp[maxn][maxn],mx; int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; a[i+n]=a[i]; } for(int i=2;i<=n+1;i++) for(int j=1;j<=2*n && i+j-1<=2*n ;j++) for(int k=j+1;k<i+j-1;k++) { int r=i+j-1; dp[j][r]=max(dp[j][r],dp[j][k]+dp[k][r]+a[j]*a[k]*a[r]); mx=max(mx,dp[j][r]); }//第一种 for(int i=2*n-1;i;i--) for(int j=i+1;j<i+n && j<=2*n;j++) for(int k=j-1;k>=i;k--)//这里正反无所谓 { dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[i]*a[k+1]*a[j+1]); mx=max(dp[i][j]); }//第二种 cout<<mx<<endl; return 0; }
相关文章推荐
- hdu 5410 CRB and His Birthday(动态规划,背包问题)
- 动态规划求解0-1背包问题
- 动态规划解决0-1背包问题
- 动态规划之——背包问题
- 0/1背包问题(二)---动态规划
- 算法导论第16章 贪心算法-0-1背包问题—动态规划求解
- poj1014 Dividing 动态规划 多重背包问题
- 背包问题——动态规划
- 九度OJ 1455 珍惜现在,感恩生活 -- 动态规划(背包问题)
- 动态规划之0/1背包问题
- HDU 2159 FATE 动态规划二维费用的背包问题
- 动态规划简单题(-背包问题)
- 10.动态规划(3)——0-1背包问题
- 【笔记】【算法学习】【动态规划】背包问题总结(1)
- 【动态规划】从子集和问题到背包问题
- 完全背包问题(动态规划)(完全背包)
- 算法导论16.2-2--动态规划(0-1背包问题)
- 动态规划☞背包问题(⊙o⊙)…
- 动态规划之0-1背包问题
- 0/1背包问题 - 动态规划(C++实现)