cdoj 1354 柱爷很忙

本文介绍了一种通过位运算和动态规划解决任务调度问题的方法,旨在帮助“柱爷”高效安排多样化的日常活动,如炒股、抢银行等,并确保有足够时间娱乐。

题目传送门

柱爷很忙

Time Limit: 1000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

柱爷很忙。

柱爷每天不仅要炒股,还要策划和实施抢银行,同时还要水群、回答IOI小朋友们问题,又或者要练习咸鱼神功。

为了能更快完成这些事,把时间拿来玩BattleBlock Theater,柱爷把要做的 N N件事的类型 ai ai原本做的顺序记录下来,计算最少要花费的时间。

万事冥冥之中俱有关联。假如柱爷做事 i i的前一件事是事 j j,所花费的时间为 (ai|aj)(ai&aj) (ai|aj)−(ai&aj),其中 |& |,&是位运算符。若柱爷做事 i i前没有做事,则柱爷要花费的时间为 ai ai

但事情总有轻重缓急之分,按原本顺序的事 i i最多能推迟到做完任意件紧接着事 i i之后的事 ji<ji+bi j,i<j≤i+bi后做,即原本顺序的事 k,k>i+bi k,k>i+bi不能在事 i i之前完成。

柱爷已经知道自己最少要花多少时间了,请问你知道吗。

Input

第一行一个数 N N,代表柱爷要做 N N件事。 1N1000 1≤N≤1000

之后 N N行,每行两个数 aibi ai,bi,代表事情的类型和重要程度。 1ai10000bi7

Output

输出一行一个数,即柱爷最少要花的时间。


题解

由于b <= 7,我们可以使用使用装压。dp[i][j][k],表示考虑前i件事,状态为j,前一件做的事距i为k。

我们考虑对于第i件事,如果它能拖,进行转移。之后考虑做j中的事情进行转移。

具体不好描述,直接上代码。

#include <bits/stdc++.h>
using namespace std;

const int Maxn = 1010, INF = 0x7f7f7f7f;
int a[Maxn], b[Maxn];
int dp[Maxn][(1 << 8) + 10][22];

void SelfMin(int &a, const int &b) {
	if (b < a) a = b; 
}

int Cal(const int &a, const int &b) {
	return (a | b) - (a & b);
}

int main() {
	int n, all = 1 << 8;
	scanf("%d", &n);
	memset(dp, 0x7f, sizeof dp);
	dp[0][all - 1][19] = 0;
	for (int i = 1; i <= n; ++i) scanf("%d%d", a + i, b + i);
	for (int i = 0; i <= n; ++i) 
	for (int j = 0; j < all; ++j)
	for (int k = 0; k < 20; ++k) 
		if (dp[i][j][k] != INF) {
			int ed = min(8, i), CanOff = INF;
			for (int p = ed - 1; p >= 0; --p) 
				if (((j >> p) & 1) == 0) SelfMin(CanOff, i - p + b[i - p]);
			if ((j >> 7) & 1) SelfMin(dp[i + 1][(j ^ (1 << 7)) << 1][min(k + 1, 19)], dp[i][j][k]);
			for (int p = ed - 1; p >= 0 && i - p <= CanOff; --p)
				if (((j >> p) & 1) == 0)
					SelfMin(dp[i][j | (1 << p)][p], 
					dp[i][j][k] + ((k == 19) ? a[i - p] : Cal(a[i - p], a[i - k])));
		}
	int ans = INF;
	for (int i = 0; i < 20; ++i) SelfMin(ans, dp[n][all - 1][i]);
	cout << ans;
	return 0;
}




### CDOJ 300 木杆上的蚂蚁 #### 题目描述 题目涉及若干只蚂蚁在一个长度为 \( L \) 的水平木杆上移动。每只蚂蚁初始位置和方向已知,当两只蚂蚁相遇时会立即掉头反向行走。目标是计算所有蚂蚁最终离开木杆的时间以及它们的顺序。 --- #### 解决方案概述 该问题的核心在于模拟蚂蚁的行为并处理碰撞事件。尽管表面上看起来需要复杂的碰撞检测逻辑,但实际上可以通过一种巧妙的方式简化问题:假设蚂蚁在碰撞时不改变方向,则可以忽略碰撞的影响[^2]。因此,只需关注每只蚂蚁到达木杆两端所需时间即可。 以下是解决问题的主要思路: 1. **输入解析** 输入数据包括测试用例数量 \( T \),每个测试用例包含木杆长度 \( L \) 和蚂蚁的数量 \( N \)。对于每只蚂蚁,记录其初始位置和移动方向(左或右)。 2. **时间和顺序计算** 对于每只蚂蚁: - 如果它朝左移动,则离木杆左侧的距离为其当前位置; - 如果它朝右移动,则离木杆右侧的距离为 \( L - \text{当前蚂蚁的位置} \)。 将这些距离存储下来,并按升序排列以确定蚂蚁离开木杆的顺序。 3. **输出结果** 输出每只蚂蚁离开木杆的时间及其编号。 --- #### Python 实现代码 以下是一个完整的 Python 实现: ```python t = int(input()) # 测试用例数量 for case in range(1, t + 1): n, l = map(int, input().split()) # 蚂蚁数量和木杆长度 ants = [] for _ in range(n): idx, pos, direction = input().split() idx = int(idx) pos = int(pos) if direction == 'L': time_to_fall = pos # 到达左边所需时间 else: time_to_fall = l - pos # 到达右边所需时间 ants.append((time_to_fall, idx)) # 按照掉落时间排序 sorted_ants_by_time = sorted(ants, key=lambda x: x[0]) # 提取原始索引以便后续匹配 original_indices = list(range(len(sorted_ants_by_time))) # 打印结果 print(f"Case #{case}:") for ant_index in original_indices: print(sorted_ants_by_time[ant_index][1], end=" ") print() ``` --- #### 关键点解释 1. **碰撞不影响总时间** 假设蚂蚁在碰撞时不改变方向,则整个过程中的最大时间为任意一只蚂蚁到最近端点的最大距离。这使得我们可以跳过复杂的状态更新操作[^2]。 2. **效率优化** 使用内置函数 `sorted` 可以高效完成排序任务,算法整体复杂度为 \( O(N \log N) \)。 3. **边界条件** 特殊情况包括仅有一只蚂蚁的情况或者所有蚂蚁都朝同一方向移动的情形。程序应能正确处理此类场景。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值