zoukankan      html  css  js  c++  java
  • BZOJ1226 SDOI2009学校食堂(状压dp)

      由于Bi<=7,考虑状压。

      如果考虑前i个位置的话,状态里需要压入前7个人后7个人,显然是跑不动的。

      那么改成考虑前i个人。于是设f[i][j][k]表示前i个人都已吃完饭,i+1后面7个人的吃饭状态为j,最后一个吃饭的人是k的答案。转移时考虑下一个吃饭的是谁即可。

      a|b-a&b=a^b。当然没什么用。

      各种情况需要考虑的非常清楚。写的跟我一样丑的话就比较难搞了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 1010
    int T,n,a[N],b[N],f[N][1<<7][16],lg2[1<<7|1],l[7];
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj1226.in","r",stdin);
        freopen("bzoj1226.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        T=read();
        for (int i=0;i<=7;i++) lg2[1<<i]=i;
        while (T--)
        {
            int n=read();
            for (int i=1;i<=n;i++) a[i]=read(),b[i]=read();
            memset(f,42,sizeof(f));
            f[0][0][7]=0;
            for (int i=0;i<n;i++)
                for (int j=0;j<(1<<min(7,n-i-1));j++)
                {
                    l[0]=min(i+1+b[i+1],n);
                    for (int k=1;k<7;k++)
                    if (!(j&(1<<k-1))) l[k]=min(l[k-1],i+k+1+b[i+k+1]);
                    else l[k]=l[k-1];
                    for (int k=0;k<16;k++)
                    if (k<=7&&i+k-7>=0||k>=9&&(j&(1<<k-9)))
                    {
                        f[i+1+lg2[j+1&-(j+1)]][j>>lg2[j+1&-(j+1)]+1][7-lg2[j+1&-(j+1)]]=
                        min(f[i+1+lg2[j+1&-(j+1)]][j>>lg2[j+1&-(j+1)]+1][7-lg2[j+1&-(j+1)]],f[i][j][k]+(i+k-7?(a[i+k-7]^a[i+1]):0));
                        for (int x=1;x<=7;x++)
                        if (!(j&(1<<x-1))&&i+x+1<=l[x-1])
                        f[i][j|(1<<x-1)][8+x]=min(f[i][j|(1<<x-1)][8+x],f[i][j][k]+(i+k-7?(a[i+k-7]^a[i+x+1]):0));
                    }
                }
            for (int i=1;i<8;i++) f[n][0][0]=min(f[n][0][0],f[n][0][i]);
            cout<<f[n][0][0]<<endl;
        }
        return 0;
    }
  • 相关阅读:
    数据结构笔记
    并查集
    计算两个数的最大公约数和最小公倍数
    行盒
    浏览器兼容性和布局
    Java中HashMap等的实现要点浅析
    关于js异步上传文件
    填充路径时所使用的 “非零环绕规则”
    XP极限编程
    假如森林里有一棵树倒下了
  • 原文地址:https://www.cnblogs.com/Gloid/p/9639870.html
Copyright © 2011-2022 走看看