小小的状压dp
直接考虑维护一个
f
(
i
,
j
,
s
)
前
i
−
1
菜
已
经
搞
定
了
。
。
。
。
上
一
次
的
菜
是
j
位
置
,
i
到
i
+
b
[
i
]
的
选
没
选
状
态
是
s
f(i,j,s)前i-1菜已经搞定了。。。。上一次的菜是j位置,i到i+b[i]的选没选状态是s
f(i,j,s)前i−1菜已经搞定了。。。。上一次的菜是j位置,i到i+b[i]的选没选状态是s
然后直接转移就好啦。。。。过水
不过细节比较多。。。比较难写?
#include<bits/stdc++.h>
#define MAXN 1000
#define maxn 1000005
using namespace std;
int T;
int n;
int t[MAXN+5],b[MAXN+5];
int f[MAXN+5][1<<9][35];
//f[i][j][s]前i-1个人已取完菜,上一次取的菜同学里i距离是j,i----b[i]的状态是s
//会出现负数,于是要加上8
void init(){
cin>>n;
for(int i = 1 ; i <= n ; i++)cin>>t[i]>>b[i];
memset(f , 0x7f , sizeof(f));
}
//f[i][s][j]---->f[i+1][s>>1][j + 7]
//f[i][s][j]---->f[i][在s里面把k标上][k]
void solve(){
f[1][0][7] = 0;
for(int i = 1 ; i <= n ; i++)for(int j = 0 ; j < (1<<8) ; j++)
for(int k = -8 ; k <= 7 ; k++){
if(f[i][j][k + 8]<maxn){
if(j & 1){f[i + 1][j>>1][k + 7] = min(f[i + 1][j>>1][k + 7] , f[i][j][k + 8]);}
else{
int minl = maxn;
for(int l = 0 ; l <= 7 ; l++){
if(!((j>>l)&1)){
if(l + i > minl)break;
minl = min(minl , i + l + b[i + l]);
f[i][j | (1<<l)][l + 8] = min(f[i][j | (1<<l)][l + 8] , f[i][j][k + 8] + ((i + k)?(t[i + k]^t[i + l]):0));
}
}
}
}
}
int maxl = maxn;
for(int i = 0 ; i <= 8 ; i++)maxl = min(maxl , f[n + 1][0][i]);
cout<<maxl<<endl;
}
int main(){
cin>>T;
while(T--){
init();
solve();
}
}