bzoj [SDOI2009]学校食堂Dining

感觉这个状压dp比较难想。。

dp[ i ][ s ][ k ] 表示前i - 1个都排好了, 从i开始的7个的取没取的状态为s, 且最后一个相对i的位置为k的最少花费。

状态转移方程

if(s & 1) dp[ i + 1][s >> 1][ k - 1] = min(dp[ i + 1][s >> 1][ k - 1], dp[ i ][ s ][ k ])

else dp[ i ][ s ^ (1 << j)][ j ] = min(dp[ i ][ s ^ (1 << j) ][ j ], dp[ i ][ s ][ k ]) 

转移的时候注意,限制条件。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define pii pair<int,int>
#define piii pair<int, pair<int,int> >

using namespace std;

const int N = 1000 + 10;
const int M = 10 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const int MOD = 1e6 + 3;
const double eps = 1e-6;
const int base = 8;

pii a[N];
int n, T, cost[N][N];
int dp[N][1 << 8][16];
int main() {
    scanf("%d", &T);
    while(T--) {
        memset(dp, inf, sizeof(dp));
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &a[i].fi, &a[i].se);
            a[i].se = min(a[i].se, n - i);
        }

        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(i == j) continue;
                cost[i][j] = a[i].fi ^ a[j].fi;
            }
        }

        dp[1][0][-1 + base] = 0;

        int up = 1 << 8;
        for(int i = 1; i <= n; i++) {
            for(int s = 0; s < up; s++) {
                for(int k = -8; k <= 7; k++) {
                    if(dp[i][s][k + base] >= inf) continue;
                    if(s & 1) {
                        int t = s >> 1;
                        dp[i + 1][t][k - 1 + base] = min(dp[i + 1][t][k - 1 + base], dp[i][s][k + base]);
                    } else {
                        int last = inf;
                        for(int j = 0; j <= 7; j++) {
                            if(s & (1 << j)) continue;

                            if(i + j > last) break;
                            last = min(last, i + a[i + j].se + j);
                            int t = s ^ (1 << j);
                            dp[i][t][j + base] = min(dp[i][t][j + base], dp[i][s][k + base] + cost[i + k][i + j]);
                        }
                    }
                }
            }
        }

        int ans = inf;
        for(int k = -8; k <= -1; k++)
            ans = min(ans, dp[n + 1][0][k + base]);

        printf("%d
", ans);
    }
    return 0;
}
/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/9122988.html