感觉这个状压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; } /* */