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


    传送门

    B和C都很小,于是想到状压。

    但状压的难点在于一个人吃饭的顺序会和其前面的人以及后面的人都有关。

    幸而最多只会和后七个人有关,我们考虑把自己以及后七个人压成一个状态。

    然后我们要知道上一次吃饭的人是谁,所以也存入状态中。只和前后七个人有关。

    设dp[i][j][k]为第1个人到第i-1个人已经打完饭,包括i自己及后7个人的状态最后吃饭的人是i+k的最小时间(k:-8~7--->负下标处理为0~15)。

    然后是如何转移:

    1.这一次是i自己吃饭

    dp[i][j][k+8]--->dp[i+1][j>>1][k+7]

    j>>1表示状态的人整体往后移一位(因为这次 i 吃饭了)。

    2.这一次是i后面的人吃饭

    那么我们枚举后面可以吃饭的人,让他们先吃饭。

    注意这是有一定范围的,不仅i本身有范围,后面的人也有范围,所以取min。

    lim=min(lim,i+p+b[i+p]);(p是枚举的后面的人)

    于是从上一次吃饭的人i+k转移到i+p

    dp[i][j|(1<<p)][p+8]=min(dp[i][j|(1<<p)][p+8],dp[i][j][k+8]+((i+k)?(di[i+k]^di[i+p]):0));

    然后是总的代码

    #include<bits/stdc++.h>
    #define N 1003
    #define LL long long
    #define mod 1000000007
    #define INF 1061109567
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    int T;
    int n;
    int di[N],b[N];
    int dp[N][1<<8][16];//第1个人到第i-1个人已经打完饭,包括i自己及后7个人的状态最后吃饭的人是i+k,k:-8~7--->0~15
    void work()
    {
        n=read();
        for(int i=1;i<=n;++i)
          di[i]=read(),b[i]=read();
        memset(dp,63,sizeof(dp));
        //printf("%d
    ",dp[1][1][1]); 
        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)continue;
                if(j&1)dp[i+1][j>>1][k+7]=min(dp[i+1][j>>1][k+7],dp[i][j][k+8]);
                else
                {
                    int lim=INF;
                    for(int p=0;p<=7;++p)
                    {
                        if((j>>p)&1)continue;
                        if(i+p>lim)break;
                        lim=min(lim,i+p+b[i+p]);
                        dp[i][j|(1<<p)][p+8]=min(dp[i][j|(1<<p)][p+8],dp[i][j][k+8]+((i+k)?(di[i+k]^di[i+p]):0));
                    }
                }
            }
        int ans=INF;
        for(int k=0;k<=8;++k)
          ans=min(ans,dp[n+1][0][k]);
        printf("%d
    ",ans); 
    }
    int main()
    {
        T=read();
        while(T--)work();
    }
    View Code
  • 相关阅读:
    团队作业9——测试与发布(Beta版本)
    团队作业8 ----第二次项目冲刺(Beta阶段)博客汇总
    【Beta】 第七次Daily Scrum Meeting
    【Beta】 第六次Daily Scrum Meeting
    【Beta】 第五次Daily Scrum Meeting
    【Beta】 第四次Daily Scrum Meeting
    【Beta】 第三次Daily Scrum Meeting
    Flask-论坛开发-5-memcached缓存系统
    Flask-论坛开发-4-知识点补充
    Flask-论坛开发-3-数据库
  • 原文地址:https://www.cnblogs.com/yyys-/p/11844709.html
Copyright © 2020-2023  润新知