P2157 [SDOI2009]学校食堂(状压dp)

原题: https://www.luogu.org/problemnew/show/P2157

题意:

n个人按顺序排队,每个人有一个服务时间T,忍耐度D,允许排在他后面的D个人进行插队。

第一个人的实际时间为0,其他人的时间为T异或前一个被服务的人的T,问总服务时间的最小值。

解析:

dp数组的维度很容易想,dp[i][j][k]代表到了第i个人,状态为j,前一个服务的人为k的最小值。

因为D最大只有7,所以j只需要表示i及后面7个人的状态即可。

注意前一个服务的人可能是i-8~i+7(前面第8个人让前面1至7个人先服务)。


在遍历人进行服务的时候,注意维护可以服务的范围。

而对于一个状态,不需要判断是否合理(有的人没被服务但是忍耐度之外的人被服务),因为我们在选择人进行服务的时候,一定会考虑到这一点。所以,只要dp值不是inf,就合理。


有一个剪枝,到了第i个人的时候,假设有一个状态已经服务了i时,可以continue了。因为当前继续的所有操作在i+1时都会再次进行。

数组开成2^7WA了好久。。。
A掉后去看别人的题解发现写的好短,但是回头看了一下时间就欣慰了

AC代码:

#include<bits/stdc++.h>
using namespace std;

int t[1009],c[1009];
int dp[1009][330][20];
int maxc;
inline int id(int i,int idx){
    return i+maxc-idx;
}

int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n;scanf("%d",&n);
        memset(dp,0x3f,(sizeof dp[0])*(n+2));
        maxc=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d",t+i,c+i);
            maxc=max(maxc,c[i]);
        }
        maxc++;
        maxc=min(maxc,n);
        int maxsta=(1<<maxc)-1;
        // i: c[i]+1 bit and more(maxc-c[i]-1) 0

        // 第一个人0费用
        int last=maxc-c[1];
        for(int i=maxc;i>=last;i--){
            if(id(1,i)>n)break;
            dp[1][1<<i-1][i]=0;
            last=max(last,i-c[id(1,i)]);
        }


        for(int i=1;i<=n;i++){
            int cmp=(1<<maxc-c[i]-1)-1 ;
            for(int sta=0;sta<=maxsta ;sta++){
                    //存在即合理
                bool f=0;
                for(int j=2*maxc;j>=1;j--)if(dp[i][sta][j]<0x3f3f3f3f)f=1;
                if(!f)continue;
                if(sta&(1<<maxc-1))continue;//剪枝

                // 遍历这个sta的可填的位置
                last=maxc-c[i];
                for(int j=maxc;j>=last;j--){
                    if(id(i,j)>n)break;
                    if(!(sta&(1<<j-1))){
                        //填
                        for(int k=2*maxc+1;k>=1;k--)//遍历前一个填的位置
                            if(k>maxc||(sta&(1<<k-1)))
                        dp[i][sta|(1<<j-1)][j]=
                            min(dp[i][sta|(1<<j-1)][j],dp[i][sta][k]+(t[id(i,k)]^t[id(i,j)]));

                        last=max(last,j-c[id(i,j)]);
                    }
                }
            }
            // 状态转移
            for(int sta=0;sta<=maxsta;sta++){
                if(sta&(1<<maxc-1)){
                    for(int j=2*maxc+1;j>=1;j--){
                        if(dp[i][sta][j]<0x3f3f3f3f)
                        dp[i+1][(sta<<1)&maxsta][j+1]=
                            min(dp[i+1][(sta<<1)&maxsta][j+1],dp[i][sta][j]);
                    }
                }
            }
        }
        int ans=0x3f3f3f3f;
        for(int j=2*maxc+1;j>=1;j--){
            ans=min(ans,dp[n][1<<maxc-1][j]);
        }
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/87371891