1. 程式人生 > >洛谷2157 學校食堂(狀壓DP)

洛谷2157 學校食堂(狀壓DP)

傳送門

【題目分析】

用命分析,這個資料範圍很狀壓。。。。。。然後就狀壓啊。

陣列dp[i][j][k]表示前i-1個人已經拿到菜,j列舉i以及他後面7個的拿菜情況,k表示上一個吃飯的位置(相對的)

注意一下列舉的上下界即可。

【程式碼~】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+10;
const int INF=0x3f3f3f3f;

int T;
int n,ans;
int dp[MAXN][1<<9][20];
struct stu{
	int x,y;
}st[MAXN];

int Read(){
	int i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

int calc(int a,int b)
{
    if(a==0) 
	  return 0;
    return st[a].x^st[b].x; 
}

void solve()
{
    for(int i=1;i<=n+1;i++){
        for(int j=0;j<(1<<8);j++){
            for(int k=-8;k<=7;k++){
                dp[i][j][k+8]=INF;
            }
        }
    }
    dp[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(dp[i][j][k+8]<INF){
                   if(j&1) 
				     dp[i+1][j>>1][k+7]=min(dp[i][j][k+8],dp[i+1][j>>1][k+7]);
                }
                else{
                    int r=INF;
                    for(int l=0;l<8;l++){
                        if(!(j&(1<<l))){
                            if(i+l>r) 
							  break;
                            r=min(r,i+l+st[i+l].y);
                            dp[i][j+(1<<l)][l+8]=min(dp[i][j+(1<<l)][l+8],dp[i][j][k+8]+calc(i+k,i+l));
                        }
                    }
                }   
            }
        }
    }
}

int main()
{
    T=Read();
    while(T--)
    {
        n=Read();
        for(int i=1;i<=n;i++) 
		  st[i].x=Read(),st[i].y=Read();
        solve();
		ans=INF;
        for(int i=-8;i<0;i++) 
		  ans=min(dp[n+1][0][i+8],ans);
        cout<<ans<<'\n';
    }
    return 0;
}