DP 经典问题(六)多重部分和问题
来源:互联网 发布:noip复赛算法总结 编辑:程序博客网 时间:2024/05/17 04:44
问题描述:
有n种不同大小的数字ai,每种各mi个,判断是否可以从这些数字之中选出若干使它们的和恰好为K。(1 <=n <= 100 , 1 <= ai,mi <=100000 , 1 <= K <= 100000)
输入:
n = 3 ,K = 17a = { 3 , 5 , 8}m = { 3 , 2 , 2}
输出
Yes(3*3+8=17}
分析:
1.刻画一个最优解的结构特征:
定义dp[i+1][j]为前 i 个数是否能加和成 j2.递归地定义最优解的值:
为了让前 i 个数加和成j,那么前 i-1个数就需要加和成 j , j - ai , …. ,j - mi*ai中的某一种。
由此,递推关系如下:
dp[i+1][j]=(0 <= k <=mi且k*ai <= j时存在使dp[i][j-k*a]为真的k)3.计算最优解的值,采用自底向上的递推法。
代码如下:
#include<cstdio>using namespace std;const int maxn = 100;int n,K;int a[maxn],m[maxn];bool dp[maxn][maxn];//dp[i+1][j]:用前i种数字是否能加和为jvoid solve(){ dp[0][0] = true;//没有数字加和当然为0了 for(int i=0;i<n;i++) { for(int j=0;j<=K;j++) { for(int k=0;k<=m[i]&&k*a[i]<=j;k++) { dp[i+1][j] |= dp[i][j-k*a[i]];//"|="为位操作运算符——位或 } } } if(dp[n][K]) printf("Yes\n"); else printf("No\n");}int main(){ scanf("%d%d",&n,&K); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<n;i++) scanf("%d",&m[i]); solve(); return 0;}
这个算法时间复杂度为O(K∑imi),所以还需要优化
优化:
1.刻画一个最优解的结构特征:
重新定义dp[i+1][j]为前i种数加和得到 j 时第 i 种数最多还能剩余多少个(不能加和得到 i 的情况为 -1)2.递归地定义最优解的值:
如果前 i-1个数加和得到 j 的话,那么第 i 个数就不用加了,就剩下mi个。
如果前 i 种数加和出 j - ai时第 i 种数还剩下k的话,用这 i 种数加和 j 时第 i 种数就能剩下k - 1个。
dp[i+1][j]=- 1.mi (dp[i][j]>=0) ;
- 2.-1 (j < ai 或者dp[i+1][j-ai]<=0) ;
- 3.dp[i+1][j-ai]-1 (其他);
3.计算最优解的值,采用自底向上的递推法。
代码如下:
#include<cstdio>#include<cstring>using namespace std;const int maxn = 100000+10;int dp[maxn],a[maxn],m[maxn];//dp[i+1][j]为用前i种数加和得到j时第i种数最多能剩余多少个 int main(){ int n,K; scanf("%d%d",&n,&K); for(int i=0; i<n; i++) { scanf("%d",&a[i]); } for(int i=0; i<n; i++) { scanf("%d",&m[i]); } memset(dp,-1,sizeof(dp)); dp[0] = 0; for(int i = 0; i<n; i++) { for(int j=0; j<=K; j++) { if(dp[j] >= 0) { dp[j] = m[i];//如果前i-1个数加和能得到j的话,第i个数就可以留下mi个 }else if(j < a[i] || dp[j - a[i]]<=0) { dp[j] = -1; }else{ dp[j] = dp[j-a[i]] - 1; } } } if(dp[K]>=0) printf("Yes\n"); else printf("No\n"); return 0;}
0 0
- DP 经典问题(六)多重部分和问题
- 经典DP 多重部分和问题
- POJ1742 (dp 多重部分和问题)
- 多重部分和问题 DP
- 多重部分和问题 dp
- [dp]多重部分和问题
- 多重部分和问题-DP动态规划
- 多重部分和问题(动态规划(DP))
- 063_多重部分和问题(DP)
- 多重部分和问题(dp 2015年安徽省赛)
- HDU1059 多重背包 多重部分和问题DP
- 多重部分和问题
- 多重部分和问题
- 多重部分和问题
- 多重部分和问题
- 多重部分和问题
- 多重部分和问题
- 多重部分和问题
- (19):接口只用于定义类型
- hessian spring实例整合
- C++第三次实验报告
- eclipse中添加tomcat8:The Apache Tomcat installation at this directory is version 8.5.13. A Tomcat 8.0 i
- 也谈一下TCP segment of a reassembled PDU
- DP 经典问题(六)多重部分和问题
- Cocos2d-x Game Development Blueprints学习
- Android一些要注意的漏洞
- 如何portingADSP中的sensor
- 将maven项目打包部署到自己的Tomcat下,可用来模拟远程服务器进行测试
- 海康相机接入 sos 流媒体 使用阿里云oss储存 实现实时转发,全天录像,历史回放,视频下载
- 表达式求值
- Ubuntu14.04下同时安装Anaconda2与Anaconda3
- 在markdown中使用HTML中的特殊符号: