洛谷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;
} 

 

posted @ 2018-11-02 22:04  Ishtar~  阅读(119)  评论(0编辑  收藏  举报