题目
以背包为标签,搜出了这么多题,按难度排序,一道一道做:
(*):下面有提到
TODO | 题目 | 难度 | 备忘录 |
---|---|---|---|
AC | 采药 | 普及- | 01背包模板 |
AC | 开心的金明 | 普及- | 01背包模板 |
AC | 小A点菜 | 普及- | 背包方案数问题 |
AC | NASA的食物计划 | 普及- | 简单的二维费用背包 |
AC | 疯狂的采药 | 普及- | 完全背包问题 |
AC | 通天之分组背包 | 普及- | 分组背包模板 |
AC | 神奇的四次方数 | 普及- | 简单的判断型完全背包(*) |
AC | 最大约数和 | 普及- | 简单的01背包+预处理 |
AC | A+B Problem(再升级) | 普及- | 完全背包方法数(*) |
AC | [HAOI2012]音量调节 | 普及- | 刷表法的多阶段决策问题 |
AC | 小书童——刷题大军 | 普及- | 两个01背包 |
AC | 三角形牧场 | 提高- | 01背包,已知推未知的状压DP |
AC | 搭配购买 | 提高- | 连通块的01背包(*) |
AC | 集合 Subset Sums | 提高- | 二维费用方法数(*) |
积木城堡 | 提高- | ||
投资的最大效益 | 提高- | ||
魔术棋子 | 提高- | ||
机器分配 | 提高- | ||
yyy2015c01的U盘 | 提高- | ||
[AHOI2001]质数和分解 | 提高- | ||
邮票 Stamps | 提高- | ||
珍珠配对 | 提高- | ||
跨河 | 提高- | ||
买干草 | 提高- | ||
牛飞盘队 | 提高- | ||
奶酪塔 | 提高- | ||
购买巧克力 | 提高- | ||
AC | 金明的预算方案 | 提高 | 简单的依赖背包,靠枚举 |
AC | 烹调方案 | 提高 | 价值变换的背包 |
选学霸 | 提高 | ||
哞哞哞Mooo Moo | 提高 | ||
虫洞Wormholes | 提高 | ||
牛的过山车 | 提高 | ||
股票市场 | 提高 | ||
拖拉机Tractor | 提高 | ||
赛斯石(赛后强化版) | 提高 | ||
不开心的金明 | 提高 | ||
AC | 垃圾陷阱 | 省选- | 复杂二维费用,状态定义与转移问题 |
AC | 多米诺骨牌 | 省选- | 抽象出来凑差值的01背包 |
宝物筛选 | 省选- | ||
飞扬的小鸟 | 省选- | ||
产品加工 | 省选- | ||
计算器写作文 | 省选- | ||
豪华游轮 | 省选- | ||
商店购物 | 省选- | ||
最少的硬币 | 省选- | ||
挤奶的时间 | 省选- | ||
小Q的棋盘 | 省选- | ||
Eden 的新背包问题 | 省选- | ||
挂饰 | 省选- | ||
消失之物 | 省选- | ||
采摘毒瘤 | 省选- | ||
小A的时钟 | 省选 | ||
语文-理理思维 | 省选 | ||
梦幻岛宝珠 | 省选 | ||
星空 | 省选 | ||
魔兽地图 | 省选 | ||
粉刷匠 | 省选 | ||
基因匹配 | 省选 | ||
苹果树 | NOI+ | ||
付公主的背包 | NOI+ | ||
秘密袭击coat | NOI+ |
PASS掉的其它的题:
(大概就是很简单或者重复的题目类型,有限的人生就不浪费在这些水题上了)
TODO | 题目 | 难度 | 备忘录 |
---|---|---|---|
PASS | 混合牛奶 | 普及- | 01背包模板 |
PASS | 扑克牌 | 普及- | 数学题 |
PASS | 总分 Score Inflation | 普及- | USACO的01背包模板 |
AC | L国的战斗之间谍 | 普及- | 简单的二维费用 |
PASS | kkksc03考前临时抱佛脚 | 普及- | 不像是背包 |
PASS | Bessie的体重问题 | 普及- | 01背包模板 |
PASS | 手链 | 普及- | 01背包模板 |
PASS | 干草出售 | 普及- | 01背包模板 |
AC | 榨取kkksc03 | 提高- | 简单的二维费用 |
PASS | 精卫填海 | 提高- | 简单的01背包 |
PASS | 樱花 | 提高- | 混合背包 |
理解
神奇的四次方数
LP1679
刚开始以为是01背包,然后就WA了,然后发现题目并没有对某一物品的使用次数进行限制。所以这里要注意,背包问题读题时的一个问题,就是应该抠字眼扣清楚每个物品使用次数,来区分各种背包模型。
A+B Problem(再升级)
1.给定一个正整数n,求将其分解成若干个素数之和的方案总数。
这题都能爆int你敢信?。。
当n=1000时,方案数为48278613741845757。
所以长点心。。这种很迷的数学题要经常记得用longlong。
2.简单的验证素数方法:
bool flag = true;
for (int i = 2; i <= trunc(sqrt(num)); i++)
if (num % i == 0) flag = false;
// trunc:小数去尾并变成int
[HAOI2012]音量调节
LP1877
本题用的是刷表法,用d[i][j]来更新d[i+1][j+v]和d[i+1][j-v]。由于决策往前往后的都用,不能确定滚动数组的枚举顺序。硬要用滚动数组的话,可以用一个二维的滚动数组。
搭配购买
P1455,连通块01背包,代码放这以供参考。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 10000 + 10;
vector<int> edge[maxn];
int n, m, c, v[maxn], w[maxn], cc, nv[maxn], nw[maxn], vis[maxn], d[maxn];
void dfs(int u, int cnt) {
nv[cnt] += v[u];
nw[cnt] += w[u];
vis[u] = 1;
for(vector<int>::iterator iter = edge[u].begin(); iter!=edge[u].end(); ++iter)
if (!vis[*iter]) {
dfs(*iter, cnt);
}
}
int main() {
scanf("%d%d%d", &n, &m, &c);
_rep(i, 1, n) scanf("%d%d", &v[i], &w[i]);
int u, v;
_for(i, 0, m) {
scanf("%d%d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cc = 0;
_rep(i, 1, n)
if (!vis[i])
dfs(i, cc++);
_for(i, 0, cc)
for (int j = c; j >= nv[i]; j--)
d[j] = max(d[j], d[j - nv[i]] + nw[i]);
printf("%d\n", d[c]);
return 0;
}
集合
LP1466
小题的细节问题:即便是这样简单题,也应该写对拍。
错误代码:(n=5时,返回1)
int main() {
scanf("%d", &n);
d[0][0] = 1;
int s = n * (n + 1) / 4;
_rep(i, 1, n)
for (int j = s; j >= 0; j--)
for (int k = s; k >= 0; k--) {
if (j >= i)
d[j][k] += d[j - i][k];
if (k >= i)
d[j][k] += d[j][k - i];
}
printf("%lld\n", d[s][s] / 2);
return 0;
}
正确代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 1000 + 10;
int n;
ll d[maxn][maxn];
int main() {
scanf("%d", &n);
d[0][0] = 1;
int s = n * (n + 1) / 4;
if (n*(n + 1) == s * 4) {
_rep(i, 1, n)
for (int j = s; j >= 0; j--)
for (int k = s; k >= 0; k--) {
if (j >= i)
d[j][k] += d[j - i][k];
if (k >= i)
d[j][k] += d[j][k - i];
}
printf("%lld\n", d[s][s] / 2);
}
else {
printf("0\n"); // 无法成功二分,自然方案数为0
}
return 0;
}