luoguP2157 [SDOI2009]学校食堂

小小的状压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)i1jii+b[i]s

然后直接转移就好啦。。。。过水

不过细节比较多。。。比较难写?

#include
#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();
	}		
}

你可能感兴趣的:(动态规划,luogu)