首页 > 编程语言 >222. 多重部分和问题(挑战程序设计竞赛)

222. 多重部分和问题(挑战程序设计竞赛)

时间:2023-01-09 14:11:06浏览次数:53  
标签:表示 竞赛 数字 int long 程序设计 222 dp

地址 https://www.papamelon.com/problem/222

有 n 种不同大小的数字 a_i,每种各 m_i个。
判断是否可以从这些数字之中选出若干个并使得它们的和恰好为 K

输入
第一行包含两个整数 n 和 K
第二行包含 n 个数表示 a 数组
第三行一行包含 n 个数表示 m 数组
1≤n≤100
1≤a i,m i ≤10^5
1≤K≤10^5
 
输出
输出 Yes 或 No
提示
2021/12/07 加强数据,可尝试重新提交
样例 1
输入
3 17
3 5 8
3 2 2
输出
Yes

解答 dp方法
常规经典动态方案
dp[i][j] 表示前i个物品凑成数目j能否成功 1表示成功 0表示失败
那么

dp[i][j] = max(dp[i-1][j],dp[i-1][j-ai],dp[i-1][a-2*ai]~~~,dp[i-1][j-k*ai]);
但是整个复杂度是O(n*K*m) 超时.
超时代码 TLE
#include <iostream>

using namespace std;

const int N = 105;
int n, K;
int dp[N][100010];
int a[N];
int m[N];

int main()
{
	cin >> n >> K;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) cin >> m[i];
	dp[0][0] = 1;
	for (long long i = 1; i <= n; i++) {
		for (long long j = 0; j <= K; j++) {
			if (dp[i - 1][j] > 0)dp[i][j] = 1;
			else {
				for (int k = 1; k <= m[i]; k++) {
					if (j >= (long long)k * a[i]) {
						dp[i][j] += dp[i-1][j - k * a[i]];
						if (dp[i][j] > 0) break;
					}
				}
			}
		}
	}

	if (dp[n][K] > 0) cout << "Yes" << endl;
	else cout << "No" << endl;


	return 0;
}

代码中,第三重循环 for (int k = 1; k <= m[i]; k++)
实际计算的是 第i个数字使用了几次,那么可以考虑使用dp[i][j]记录下第i个数字达到j的和的时候,第i个数字使用了几个,就可以优化掉第三重循环
此时dp[i][j] 表示的意义不再是dp[i][j] 表示前i个物品凑成数目j能否成功 1表示成功 0表示失败
而是 前 i 个数字凑成数目j,第 i 个数字使用了几个


#include <iostream>

using namespace std;

const int N = 105;
int n, K;
int dp[N][100010];
int a[N];
int m[N];


//dp[i][j]表示前i个数字达到j的和时候 第i个数字使用的最小值
int main() {
	cin >> n >> K;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) cin >> m[i];
	 
	memset(dp,-1,sizeof dp);
	dp[0][0] = 1;

	for (int i = 1; i <= n; i++) {
		for (int j = 0; j <= K; j++) {
			if (dp[i - 1][j] >= 0) dp[i][j] = 0;
			if (dp[i][j] == -1 && j >= a[i]&&dp[i][j-a[i]]>=0) {
				if (dp[i][j - a[i]] + 1 <= m[i]) {
					dp[i][j] = dp[i][j - a[i]] + 1;
				}
			}
		}
	}

	//cout << dp[n][K] << endl;
	if (dp[n][K] >= 0) cout << "Yes" << endl;
	else cout << "No" << endl;


	return 0;
}

标签:表示,竞赛,数字,int,long,程序设计,222,dp
From: https://www.cnblogs.com/itdef/p/17036892.html

相关文章

  • C++面向对象程序设计
    目录第二章类和对象构造函数析构函数对象数组第三章深入理解类和对象3.5常对象与常成员3.6动态创建对象和释放对象3.7对象的生存期3.8程序实例第四章静态成员与友元......
  • 2022-2023-1 20221320 《计算机基础与程序设计》第十九周学习总结
    学期(2022-2023-1)学号(20221320)《计算机基础与程序设计》第十九周学习总结作业信息各项要求具体内容<班级的链接>2022-2023-1-计算机基础与程序设计<作业要......
  • 面向对象程序设计 第一章 绪论
    第一章绪论目录·计算机程序设计语言的发展·面向对象的方法·面向对象的软件开发·程序开发的过程·信息的表示与存储计算机程序·计算机的工作使用程序......
  • 北京大学程序设计MOOC-魔兽世界大作业(三)
    程序设计-魔兽世界大作业上一篇作业解析与代码:​​魔兽世界-装备​​项目OJ提交:​​魔兽世界-开战​​思路与类架构题目需求分析与设计魔兽世界是两方阵营战斗的游戏,双方......
  • C语言程序设计课程设计[2023-01-07]
    C语言程序设计课程设计[2023-01-07]C语言程序设计课程设计要求一、课程设计目的1.进一步掌握和利用C语言进行程设计的能力;2.进一步理解和运用结构化程设计的思想和......
  • 《随机算法在信息学竞赛中的应用》做题记录
    目录《随机算法在信息学竞赛中的应用》做题记录MSTONESProblemSolutionP3567[POI2014]KUR-CouriersProblemSolutionCF364DGhdProblemSolutionTKCONVEXProblemSolutionP12......
  • 222
    classGrandparent{publicGrandparent(){System.out.println("GrandParentCreated.");}publicGrandparent(Stringstring){......
  • 竞赛图
    竞赛图,是每两个点之间都有一条有向边的图。因为有一种模型是两者之间比赛谁能赢,赢的人对输的人连一条边,因此叫做竞赛图。竞赛图的性质:对SCC缩点之后是一条链式结构,类......
  • JIT寒假算法竞赛集训第七场动态规划入门
    动态规划入门本页面用到的网站:洛谷:https://www.luogu.com.cn/acwing:https://www.acwing.com/引入:斐波那契数列f[n]=1(n0||n1)f[n]=f[n-1]+f[n-2](n>1)递归:int......
  • Rust 程序设计语言(8)
    title:Rust程序设计语言(8)date:2023-01-03updated:2023-01-05comments:truetoc:trueex......