题目
描述 Description
神仙姐姐来到一个美丽的地方,不过美中不足的是那儿有好些秃山……
由于神仙过于爱美,由不得有半点瑕疵,所以她想用仙力把这些儿秃山通通消灭掉!由于消灭一座山可能要消耗掉一些Hp Or Mp Or Rp……但是有的时候不必考虑那么多,你有可能只需要考虑HP和MP,甚至仅仅考虑HP.(难道是请了哪位俊男来帮忙…….?)
输入格式 Input Format
第一行有两个整数n (0<n<=100)和m (1<=m<=5),分别表示山的数量和需要考虑的身体数值种类.
第二行m个整数 v1—vm,表示神仙各种数值的初始值(各种数值消耗后不会回复);
第三行到第n+2行,分别是这n座山的资料,每行m+1个数。每行第一个数是消灭掉这座山可以得到的美观度,第二到第m+1个数分别表示消灭掉这座山消耗的各种数值(对应第二行的数值)
输出格式 Output Format
输出神仙姐姐可以得到的最大美观度(每种数值最后不可消耗到<0);
题解
- 首先很容易想到这道题一种暴力的解法,因为题中的 m ⩽ 5 m\leqslant5 m⩽5,那么我们很容易想到开一个五维的 F F F数组进行01背包,但这无疑会造成很大的空间浪费。
- 那么我们就想到的状态压缩。
- 如果这道题只有一维,那就十分容易,可如果他有两维,我们就需要思考一下。
- 假设这两维中每一维中最大的数字分别为 a , b a, b a,b,那么他们所能表示的最大的一维数字即为 ( a + 1 ) ∗ ( b + 1 ) − 1 (a+1)*(b+1)-1 (a+1)∗(b+1)−1
- 那么我们推广到 n n n维来看
- 设这几个进制数为 t 1 , t 2 , t 3 , ⋯   , t n t_1, t_2, t_3, \cdots, t_n t1,t2,t3,⋯,tn,转化为 10 10 10进制对应的数为 m 1 , m 2 , m 3 , ⋯   , m n m_1,m_2,m_3,\cdots,m_n m1,m2,m3,⋯,mn
- 那么 m i = ∏ k = i + 1 n t k + 1 m_i= \prod_{k = i+1}^{n} t_k+1 mi=∏k=i+1ntk+1
- 这样的话我们就能将题中所给的 m m m转化为一个十进制数了,在我们状态压缩过后,题目就变成了一道简单的背包问题。
code
const int maxn = 105;
const int maxm = 1e5 + 100;
const int inf = 0x3f3f3f3f;
int n;
int m;
int num;
int v[maxn];
int t[maxn];
int p[maxn];
int f[maxm];
int weigh[maxn];
int w[maxn][maxn];
int main() {
read(n), read(m); // 快读
for (int i = 1; i <= m; ++i)
read(p[i]);
t[1] = 1;
for (int i = 2; i <= m + 1; ++i)
t[i] = t[i - 1] * (p[i - 1] + 1);
num = t[m + 1] - 1;
for (int i = 1; i <= n; ++i) {
read(v[i]);
for (int j = 1; j <= m; ++j) {
read(w[i][j]);
weigh[i] += w[i][j] * t[j];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = num; j >= weigh[i]; j--) {
int k;
for (k = 1; k <= m; ++k)
if (j % t[k + 1] / t[k] < w[i][k]) break;
if (k > m)
f[j] = max(f[j], f[j - weigh[i]] + v[i]);
}
}
write(f[num]); // 快写
return 0;
}