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 }
View Code

猜你喜欢

转载自www.cnblogs.com/cychester/p/9590500.html