【hdu3732】Ahui Writes Word——多重背包

本文探讨了Ahui Writes Word这一问题,指出原题看似01背包,但实际是多重背包问题。由于数据特点,存在单词的重复,从而转化为多重背包。解决方案中,当单词数量与复杂度乘积超过复杂度上限时,视作完全背包处理,否则按01背包方式,利用二进制优化。最后通过动态规划dp[i]表示容量为i时的最大价值,输出dp[C]得出答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

Ahui Writes Word

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2583    Accepted Submission(s): 937


Problem Description
We all know that English is very important, so Ahui strive for this in order to learn more English words. To know that word has its value and complexity of writing (the length of each word does not exceed 10 by only lowercase letters), Ahui wrote the complexity of the total is less than or equal to C.
Question: the maximum value Ahui can get.
Note: input words will not be the same.
 

Input
The first line of each test case are two integer N , C, representing the number of Ahui’s words and the total complexity of written words. (1 ≤ N ≤ 100000, 1 ≤ C ≤ 10000)
Each of the next N line are a string and two integer, representing the word, the value(Vi ) and the complexity(Ci ). (0 ≤ Vi , Ci ≤ 10)
 

Output
Output the maximum value in a single line for each test case.
 

Sample Input
  
5 20 go 5 8 think 3 7 big 7 4 read 2 6 write 3 5
 

Sample Output
  
15
Hint
Input data is huge,please use “scanf(“%s”,s)”
 

Author
Ahui
 

Source
描述:每一个单词都有它的复杂度和价值,现在给你N个单词(1~1e6)和复杂度上限C(1~1e5),再给你N的单词的价值v和复杂度c(0~10),求能组合出的不超过复杂度上限的最高价值。

题解:这题乍一看是一个01背包问题,但是时间复杂度是o(N*C)肯定会T,注意到价值和复杂度的组合数一共只有121种,而会给我们1e6个单词,那么一定会有重复的,于是我们要合并重复的之后,每一种单词有一定数量,这就转化成了多重背包问题,在具体求解时,针对每一种单词,如果数量乘以复杂度超过了复杂度上限,那么这种单词就当作完全背包来做(相当于数量没有上限),而不足的就是01背包,而且01背包还可以用二进制来优化拆分,会更快。dp[i]表示装入容量为i的背包可以获得的最大价值(不一定装满),最后输出dp[C]即可。

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

const int maxn = 126;
int dp[10005], v[maxn], w[maxn], c[maxn];
int C;

struct word
{
	int v;
	int w;
	bool operator< (const word b)
	{
		return w < b.w || (w == b.w && v < b.v);
	}

	bool operator == (const word b)
	{
		return v == b.v && w == b.w;
	}
}wo[100005];

void zero_one_pack(int v, int w)
{
	for (int i = C; i >= w; i--)
		dp[i] = max(dp[i], dp[i - w] + v);
}

void complete_pack(int v, int w)
{
	for (int i = w; i <= C; i++)
		dp[i] = max(dp[i], dp[i - w] + v);
}

void multi_pack(int v, int w, int c)
{
	if (c*w >= C)
	{
		complete_pack(v, w);
	}
	else
	{
		int k = 1;
		while (k < c)
		{
			zero_one_pack(v*k, w*k);
			c -= k;
			k *= 2;
		}
		zero_one_pack(c*v, c*w);
	}

	return;
}

int main()
{
	//freopen("input.txt", "r", stdin);
	int	N;
	char s[20];
	
	while (scanf("%d%d", &N, &C) ==2)
	{
		memset(dp, 0, sizeof(dp));
		for (int i = 0; i < N; i++)
		{
			scanf("%s %d%d", s, &wo[i].v, &wo[i].w);
		}
		sort(wo, wo + N);
		int num = 0;                              //计算种数
		w[0] = wo[0].w;
		v[0] = wo[0].v;
		c[0] = 1;
		for (int i = 1; i < N; i++)              //合并
		{
			if (wo[i] == wo[i-1])
			{
				c[num]++;
			}
			else
			{
				num++;
				v[num] = wo[i].v;
				w[num] = wo[i].w;
				c[num] = 1;
			}
		}

		for (int i = 0;i <= num; i++)
		{
			multi_pack(v[i], w[i], c[i]);
		}
		printf("%d\n", dp[C]);
	}

	return 0;
}


HDU 3732 (Queue) 是一个经典的队列操作题目,在这个题目的设定下,你需要处理一系列关于入队、出队的操作,并最终输出特定的结果。这类问题通常会涉及到数据结构中的“队列”这一概念。 ### 题目概述 在 HDU 3732 中,你将面对的是一个标准的队列入栈和出栈的问题变种。它可能会给出一些序列化的指令集,包括: - 入队(push) - 出队(pop) 并且最后询问某些元素的状态或顺序等信息。 ### 解决思路 为了应对这个问题,你可以采用双端队列的数据结构或者两个栈模拟队列的方式来解决问题。以下是具体的步骤: 1. **初始化**:创建所需的辅助变量及容器,如 `queue` 或者一对用于模拟队列行为的栈 (`stackIn`, `stackOut`)。 2. **处理命令流**:遍历输入命令列表,根据不同类型的命令做相应动作: - 对于每一个 push 操作直接添加到指定位置; - 当遇到 pop 命令,则从头部移除元素;如果是用栈实现的话需要特殊处理,比如先全部倒入另一个栈再弹出顶部元素作为当前最先进来的那个值被移走。 3. **生成结果**:按照题目要求整理并返回正确的输出内容。 4. **注意事项** - 确保每次只对有效范围内的索引执行插入/删除操作。 - 考虑边界条件,例如空队列出队等情况下的异常处理。 ### 示例代码片段(Python 实现) ```python from collections import deque def process_queue_commands(commands): queue = deque() for command in commands: if "in" == command[0]: value = int(command.split()[1]) queue.append(value) elif "out" == command and len(queue)>0: print("Pop element:", queue.popleft()) # 示例用法 commands = ["5", "in 8", "in 9", "out"] process_queue_commands(commands[1:]) ``` 请注意实际比中给定的具体细节可能有所差异,请参考原题描述进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值