首页 > 其他分享 >洛谷P1064题解

洛谷P1064题解

时间:2022-10-26 22:00:12浏览次数:86  
标签:洛谷 主件 题解 选取 物品 附件 obj include P1064

原题

P1064 [NOIP2006 提高组] 金明的预算方案


思路概述

题意分析

给定一个体积为 \(n\) 的背包和 \(m\) 个物品。每个物品通过 \((\text{价值},\text{体积})\) 的形式表示为 \((p_i·v_i,v_i)\),同时部分物品还对应了唯一的一个前驱 \(q_i\),只有前驱被选入背包的时候该物品才能被选取。求最后能取得的最大价值。

思路简述

有点意思的01背包变式,对于一个没有对应主件也没有对应附件的物品,操作策略与01背包无异;对于相互对应的主件和附件,由于每个主件最多两个附件(为方便表述,笔者称相互对应的主件与附件为一组物品),其所有的选取情况只有最多四种:只选取主件、选取主件和第一个附件、选取主件和第二个附件、同时选取主件和所有附件。


算法实现

关于背包的第二重循环

由于本题中一组物品的所有选取方式对应了多个不同的体积,所以此处就不需要将第二重循环设置为 \(V→v_i\),而是设为 \(V→0\)。

关于多种状态的选取

由于一组物品的多个体积的选取过程中可能出现 \(V-v_i<0\) 的情况,所以需要在选取过程中判定这一点。为方便编码,笔者选择把这一步封装成自定义函数。


AC code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<ctime>
#define RI register int
using namespace std;
const int maxn=4e4+10;
typedef struct
{
	int w,v,pre;
	int nex[3];
}object;
typedef struct
{
	int w,v;
}node;
typedef struct
{
	int l,r;
}range;
object obj[maxn];
node e[maxn<<2];
range rg[maxn];
int n,m,cnt;
int f[maxn<<4];
inline void init(void);
inline int calc(int x,int v);
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin >> n >> m;n/=10;
	for(RI i=1;i<=m;++i)
	{
		cin >> obj[i].v >> obj[i].w >> obj[i].pre;
		obj[i].w*=obj[i].v;obj[i].v/=10;
		if(obj[i].pre) obj[obj[i].pre].nex[++obj[obj[i].pre].nex[0]]=i;
	}
	init();
	for(RI i=1;i<=m;++i)
		if(rg[i].l && rg[i].r)
			for(RI j=n;j>=0;--j)
				f[j]=max(f[j],calc(i,j));
	printf("%d",f[n]);
	fclose(stdin);fclose(stdout);
	return 0;
}
inline void init(void)
{
	/*将一个主件及其附件拆为多个单独的物品 拆分出的物品继承主附件的权值与体积和*/
	/*同时开空间存储当前主件及其附件所对应的物品下标*/
	for(RI i=1;i<=m;++i)
		if(obj[i].pre) continue;
		else if(!obj[i].nex[0]) 
		{
			e[++cnt]=(node){obj[i].w,obj[i].v};
			rg[i]=(range){cnt,cnt};
		}
		else if(obj[i].nex[0]==1)
		{
			e[++cnt]=(node){obj[i].w,obj[i].v};
			e[++cnt]=(node){obj[i].w+obj[obj[i].nex[1]].w,obj[i].v+obj[obj[i].nex[1]].v};
			rg[i]=(range){cnt-1,cnt};
		}
		else
		{
			e[++cnt]=(node){obj[i].w,obj[i].v};
			e[++cnt]=(node){obj[i].w+obj[obj[i].nex[1]].w,obj[i].v+obj[obj[i].nex[1]].v};
			e[++cnt]=(node){obj[i].w+obj[obj[i].nex[2]].w,obj[i].v+obj[obj[i].nex[2]].v};
			e[++cnt]=(node){obj[i].w+obj[obj[i].nex[1]].w+obj[obj[i].nex[2]].w,obj[i].v+obj[obj[i].nex[1]].v+obj[obj[i].nex[2]].v};
			rg[i]=(range){cnt-3,cnt};
		}
	return;
}
inline int calc(int x,int v)
{
	RI ret=0;
	for(RI i=rg[x].l;i<=rg[x].r;++i)
		if(v>=e[i].v)/*考虑是否买得下当前的物品*/
			ret=max(ret,f[v-e[i].v]+e[i].w);/*若买得下 就更新状态*/ 
	return ret;
}

标签:洛谷,主件,题解,选取,物品,附件,obj,include,P1064
From: https://www.cnblogs.com/frkblog/p/16830238.html

相关文章

  • CF Round #829 题解 (Div. 2)
    F没看所以摆了.看拜月教教主LHQ在群里代打恰钱/bx目录A.TechnicalSupport(*800)B.KevinandPermutation(*800)C.MakeNonzeroSum(C1*1300,C2*1500)D.F......
  • 洛谷 P7003
    考虑当左端点固定时,区间的\(\&\)和至多有\(\logw\)种,因为\(1\)的数量是单调不升的。所以我们可以枚举区间左端点\(i\),然后ST表预处理区间\(\&\)和+二分求出......
  • Error: Cannot find module 'gifsicle'问题解决
    运行报错 Error:Cannotfindmodule'gifsicle'解决办法:删除nodu_modules下的image-webpack-loader包npmuninstallimage-webpack-loader重新安装npminstall......
  • CF 464C Substitutes in Number 题解
    前置知识:\((a+b)\equiv(a\bmodp+b\bmodp)\pmod{p}\)。同余定理使用后不能再修改数字。那么为了能用这个公式,我们倒序处理每个数字。定义\(d_i\)为\(10\)的位数\(......
  • 2022/10/26 考试题解
    又被抓摆了/kkT4(T3?)CactustoTreelinkSolutiontmd,连tm\(\Theta(n^2)\)都没有看出来!!!!!!/fn考虑\(\Theta(n^2)\)怎么做,其实就是对于每一个点直接BFS(似乎对正解也没有......
  • 洛谷P2512 [HAOI2008]糖果传递
    SLOJP1117.糖果传递题目描述有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为11。输入格式小朋友个数n,下面n行ai​......
  • 洛谷 P6453
    设第\(i\)列高\(h_i\),建立序列\(h_i\)的小根笛卡尔树,然后树形DP。发现这样就将原来不规整的图形剖分成若干个矩形:我们发现,这样构成的若干个矩形正好对应小根笛卡......
  • 洛谷优秀油猴插件推荐
    前言转载自眭然的博客,有改编和新增下载链接油猴zip1.先打开edge浏览器的扩展(其他浏览器应该也可以加扩展,不过edge最好)2.打开开发者模式和允许来自其他应用商店的......
  • CSPS2019 括号树 题解
    链的部分分我们设f[i]表示以i结尾的括号序列有多少个,那么i的实际答案就是f的前缀和显然,所有左括号和不能匹配的右括号的f均为0对于每一个能匹配的右括号i,我们找到与之......
  • EasyCVR数据库优化:ehome设备表不能同步更新的问题解决
    EasyCVR视频融合云平台可支持多协议、多设备接入,包括国标GB28181、RTMP、RTSP/Onvif、海康SDK、大华SDK、Ehome等协议,同时也能分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视......