BZOJ 4145 [AMPPZ2014] The Prices 解题报告

感觉也是一个小清新题。。

我们考虑设立状态 $Dp[i][s]$ 表示考虑了前 $i$ 个商店后,购买状态为 $s$ 的最小花费。

转移的话就枚举每个商店 $i$,首先令:

$$Dp[i][s] = Dp[i - 1][s] + D[i]$$

这个过程表示到达这个商店。

然后枚举每个状态 $s$,然后枚举每个不在 $s$ 里的物品 $j$,令:

$$Dp[i][s + {j}] = min(Dp[i][s + {j}], Dp[i][s] + Cost[i][j])$$

这个过程就相当于是进行了一次 01 背包。

最后还要令 $Dp[i][s] = min(Dp[i][s], Dp[i - 1][s])$ 看看在商店 $i$ 时的购买计划是否划算。

令全集是 $S$,那么最后答案就是 $Dp[n][S]$ 了。

时间复杂度 $O(nm2^m)$,空间复杂度 $O(n2^m)$。

 1 #include <cstdio>
 2 #define min(a, b) ((a) < (b) ? (a) : (b))
 3 #define N 100 + 5
 4 #define M 16 + 5
 5 #define SIZE 1 << 16
 6 #define INF 593119681
 7 
 8 int n, m, W[N], Map[N][M], Dp[N][SIZE];
 9 
10 int main()
11 {
12     scanf("%d%d", &n, &m);
13     for (int i = 1; i <= n; i ++)
14     {
15         scanf("%d", W + i);
16         for (int j = 1; j <= m; j ++)
17             scanf("%d", Map[i] + j);
18     }
19     for (int s = 0; s < (1 << m); s ++)
20         Dp[0][s] = INF;
21     Dp[0][0] = 0;
22     for (int i = 1; i <= n; i ++)
23     {
24         for (int s = 0; s < (1 << m); s ++)
25             Dp[i][s] = Dp[i - 1][s] + W[i];
26         for (int j = 1; j <= m; j ++)
27             for (int s = 0; s < (1 << m); s ++)
28                 if ((s & (1 << j - 1)) == 0)
29                     Dp[i][s ^ (1 << j - 1)] = min(Dp[i][s ^ (1 << j - 1)], Dp[i][s] + Map[i][j]);
30         for (int s = 0; s < (1 << m); s ++)
31             Dp[i][s] = min(Dp[i][s], Dp[i - 1][s]);
32     }
33     printf("%d
", Dp[n][(1 << m) - 1]);
34     
35     return 0;
36 }
4145_Gromah
原文地址:https://www.cnblogs.com/gromah/p/4592207.html