状压dp-基础题目2([USACO12MAR] Cows in a Skyscraper G)

题目链接

做题反思

这题我一开始没过Subtask #1,当时想的是dp数组存储电梯承载奶牛集合s(二进制转整数)需要的最少趟数,再开一个数组z,存储奶牛集合s的重量,如果zs>w,则让zs%w。这是不对的,比如Subtask #1的数据最大载重w为10,4头奶牛的重量为9,9,9,2,用这个思路,答案是3。问题就在于这种做法会把奶牛"分身"乘坐电梯,比如前两头奶牛,有一头奶牛会有1重量在1趟电梯,另外8重量在另一趟电梯,这就有问题了。

题目正解
  • 数组定义
    我们定义一个数组dp,dpij表示第i趟运送奶牛集合j的重量。初始化dp数组为0x3f3f3f3f,dp00=0,dp11\<\<(i-1)=ci
  • 状态转移
    外层遍历趟数,循环遍历为i,范围是1至n。内层循环遍历集合j,范围0至(1<<n),我们看一下用i趟运送奶牛集合j是否能实现,如果可以,则再遍历新加入奶牛,循环变量k,范围是1至n。通过移位运算和与运算判断集合j时候有奶牛k,如果没有就看一下当前dpij+ck是否大于w,如果是,要新开一趟,dpi+1j\|(1\<\<(k-1))=min(dpi + 1j \| (1 \<\< k - 1),ck);否则, dpij \| (1 \<\< k - 1) = min(dpij \| (1 \<\< k - 1), dpij + ck)。
  • 输出答案
    循环变量i遍历1至n,输出第一个dpi(1\<\<0x3f3f3f3f的值,结束。
AC代码
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int w, c[20], dp[20][1 << 20], n;

int main() {
	cin >> n >> w;
	memset(dp, 0x3f, sizeof(dp));
	dp[0][0] = 0;
	for (int i = 1; i <= n; i++) {
		cin >> c[i];
		dp[1][1 << (i - 1)] = c[i];
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j < (1 << n); j++) {
			if (dp[i][j] < 0x3f3f3f3f) {
				for (int k = 1; k <= n; k++) {
					if (!((1 << k - 1)&j)) {
						if (dp[i][j] + c[k] > w)
							dp[i + 1][j | (1 << k - 1)] = min(dp[i + 1][j | (1 << k - 1)], c[k]);
						else
							dp[i][j | (1 << k - 1)] = min(dp[i][j | (1 << k - 1)], dp[i][j] + c[k]);
					}
				}
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		if (dp[i][(1 << n) - 1] < 0x3f3f3f3f) {
			cout << i;
			break;
		}
	}
	return 0;
}
相关推荐
Jerry2 小时前
LeetCode 1002. 查找共用字符
算法
无限的鲜花2 小时前
协程本质是函数加状态机——零基础深入浅出 C++20 协程
c++·算法·c++20
精明的身影2 小时前
C++自学之路1:Hello world
开发语言·c++
旖-旎3 小时前
《LeetCode 64 最小路径和 || LeetCode 174 地下城游戏》
c++·算法·leetcode·动态规划
森林古猿13 小时前
再论斜率优化
c++·学习·算法
万法若空3 小时前
【数学-简单数论】同余中的逆
线性代数·算法
水利行业RTU手艺人3 小时前
RTU固件中的“数据保险箱”——离线数据补发系统设计
c++·stm32·单片机·物联网
凯瑟琳.奥古斯特4 小时前
力扣1009补码解法C++实现
开发语言·c++·算法·leetcode·职场和发展
KaMeidebaby4 小时前
卡梅德生物技术快报|蛋白的叠氮基修饰:实操解析:核酸模板耦合蛋白的叠氮基修饰实现靶蛋白定点共价标记
前端·人工智能·物联网·算法·百度