【题解】Luogu P2157 [SDOI2009]学校食堂

原题传送门:P2157 [SDOI2009]学校食堂

一看题目就知道是状压dp

设f[i][j][k]表示第1到i-1个人都吃完了饭,第i个人以及后面的7个人是否打饭的状态为j,当前最后打饭的人的编号为i+k(-8<=k<=7)

开始设计状态转移方程

当j&1为真,表示i之后的7个人中,不再会有人插队到i之前

可得:f[i + 1][j >> 1][k - 1]=Min(f[i + 1][j >> 1][k -1],f[i][j][k])

当j&1为假,可以选i和后面7个人之一来打饭

枚举h从0到7

可得方程:f[i][j | (1 << h) ][h]=Min(f[i][j | (1 << h) ][h],f[i][j][k] + time(i+k,i+h)

time(i,j)的意义是在第i个人之后给第j个人打饭所需代价

当然,这个转移需要考虑到忍耐度的问题。这样,在i和后面的7个人,不是每一个还未打饭的人都可以先打饭的。

因为编号在他之前的所有未打饭的人的忍耐度必须能忍受这个人在他们之前打饭。

所以,在这里用了一个变量x来统计了一下,表示到目前为止的未打饭的人的忍受范围(注意,不是忍耐度,忍受范围是指能忍受在其之前打饭的最大位置)的最小值

对于任何一个人,如果i+h>x,就表示他无法满足编号在他之前的所有人的忍受范围,就不要考虑这个人了。

状态转移就这么多

最后ans是Min(f[n + 1][0][k]) (-8 <= k <=0 )

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define N 1005
#define inf 0x3f3f3f3f
using namespace std;
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
inline int Min(register int a,register int b)
{
    return a<b?a:b;
}
int n,T[N],B[N],f[N][1<<8][20];
int main()
{
    int t=read();
    while(t--)
    {
        n=read();
        for(register int i=1;i<=n;++i)
            T[i]=read(),B[i]=read();
        memset(f,inf,sizeof(f));
        f[1][0][7]=0;
        for(register int i=1;i<=n;++i)
            for(register int j=0;j<(1<<8);++j)
                for(register int k=-8;k<=7;++k)
                    if(f[i][j][k+8]!=inf)
                    {
                        if(j&1)
                            f[i+1][j>>1][k+7]=Min(f[i+1][j>>1][k+7],f[i][j][k+8]);
                        else
                        {
                            int x=inf;
                            for(register int h=0;h<=7;++h)
                                if(!((j>>h)&1))
                                {
                                    if(i+h>x)
                                        break;
                                    x=Min(x,i+h+B[i+h]);
                                    f[i][j|(1<<h)][h+8]=Min(f[i][j|(1<<h)][h+8],f[i][j][k+8]+(i+k?(T[i+k]^T[i+h]):0));
                                }
                        }
                    }
        int ans=inf;
        for(register int k=0;k<=8;++k)
            ans=Min(ans,f[n+1][0][k]);
        printf("%d\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/9743517.html

时间: 2024-11-09 15:08:36

【题解】Luogu P2157 [SDOI2009]学校食堂的相关文章

P2157 [SDOI2009]学校食堂Dining

题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示. 由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为"|&

P2157 [SDOI2009]学校食堂

题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示. 由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为“|”

P2157 [SDOI2009]学校食堂 状压DP

题意: 排队买饭,时间为前一个人和后一个人的异或和,每个人允许其后面B[i] 个人先买到饭,问最少的总用时. 思路: 用dp[i][j][k] 表示1-i-1已经买好饭了,第i个人后面买饭情况为j,最后一个打饭的是i+k. #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <i

【BZOJ1226】[SDOI2009]学校食堂Dining 状压DP

[BZOJ1226][SDOI2009]学校食堂Dining Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示.由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,o

[LuoguP2157][SDOI2009]学校食堂_状压dp

学校食堂 题目链接:https://www.luogu.org/problem/P2157 数据范围:略. 题解: 发现$B$特别小,很容易想到状压. 即在$dp$的时候弄出来$f_{(i,j,k)}$表示前$i - 1$个都打完了饭,状态$j$也已经打完饭了,当前打饭的是$i$,上一个打饭的是$i+k$这样能存的下. 转移的话需要枚举状态,但是没必要枚举完全因为毕竟是长度只有$7$. 看见了相邻两个人转移的代价之后,以为可以根据位运算能搞出点什么东西发现啥也搞不动. 我们可以适当地省略一些条件

[BZOJ1226][SDOI2009]学校食堂Dining

试题描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示.由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为"|&q

bzoj1226: [SDOI2009]学校食堂Dining 状压dp

Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示.由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运

[SDOI2009]学校食堂

题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示. 由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为"|&

bzoj 1226 [SDOI2009]学校食堂Dining(状压DP)

Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示.由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运