Luogu 2157 [SDOI2009]学校食堂 - 状压dp
Solution
比较好想的dp, 但是坑不少QAQ, 调半天
由于容忍度 $b_i$<= 7, 所以可以考虑将第$i$个人接下来的$b_i$ 个人作为一个维度记录状态。
于是我们定义数组$f[ i ][ S ]$ 表示前$i-1$个人都已经拿到了菜, S表示$i$和接下来$b_i$个人是否拿到了菜。
然后依次枚举$i$ :第$i$个人, $S$ : $i$与接下来$b_i$个人是否拿到菜, $nt$ : 下一次谁拿菜, $fr$ : 上一次谁拿菜
还需要通过$judge$来判断该状态是否可行, 最后进行$dp$
具体看代码里的$jud$ 和$dp$ 函数
Code
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #define rd read()
5 #define rep(i,a,b) for(register int i = (a); i <= (b); ++i)
6 #define per(i,a,b) for(register int i = (a); i >= (b); --i)
7 using namespace std;
8
9 const int N = 1e3 + 100;
10 const int base = 10;
11 const int inf = 1061109567;
12
13 int tas[N], bac[N], f[N][300][25];
14 int n, T;
15
16 int read() {
17 int X = 0, p = 1; char c = getchar();
18 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
19 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
20 return X * p;
21 }
22
23 int jud(int now, int S, int nt, int fr) {
24 if(f[now][S][fr +base] >= inf) return 0;
25 if((S >> nt) & 1) return 0;
26 if(!((S >> fr) & 1) && fr >= 0) return 0;
27 if(now + fr < 0) return 0;
28 rep(i, now, now + nt) if(!((S >> (i - now)) & 1) && now + nt > i + bac[i]) return 0;
29 return 1;
30 }
31
32 void dp(int now, int S, int nt, int fr) {
33 int ntS = S | (1 << nt), tmp = inf; //ntS表示给nt拿完菜的状态
34 if(now + fr) tmp = min(tmp, f[now][S][fr + base] + (tas[now + nt] ^ tas[now + fr]));
35 else tmp = min(tmp, f[now][S][fr + base] + 0);
36 nt += now;
37 for(; ntS & 1; ntS >>= 1) {
38 f[now][ntS][nt - now + base] = min(f[now][ntS][nt - now + base], tmp);
39 //printf("%d %d %d\n", now, ntS, nt);
40 now++;
41 }
42 f[now][ntS][nt - now + base] = min(f[now][ntS][nt - now + base], tmp);
43 //printf("%d %d %d\n", now, ntS, nt);
44 }
45
46 void work() {
47 memset(f, 63, sizeof(f));
48 n = rd;
49 rep(i, 1, n) tas[i] = rd, bac[i] = rd;
50 f[1][0][-1 + base] = 0;
51 rep(i, 1, n) rep(j, 0, (1 << (bac[i] + 1)) - 1) rep(k, 0, bac[i]) rep(fr, -8, 7) {//fr必须从-8枚举
52 if(!jud(i, j, k, fr)) continue;
53 dp(i, j, k, fr);
54 }
55 int ans = inf;
56 rep(i, -7, 7) ans = min(ans, f[n][1][i + base]);
57 printf("%d\n", ans);
58 }
59
60 int main()
61 {
62 T = rd;
63 rep(i, 1, T) work();
64 }