题目大意

  小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭。学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴。当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示。 由于人手不够,食堂每次只能为一个人做菜。做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的。其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为“|”和“&”。学生数目相对于这个学校还是比较多的,吃饭做菜往往就会花去不少时间。因此,学校食堂偶尔会不按照大家的排队顺序做菜,以缩短总的进餐时间。虽然同学们能够理解学校食堂的这种做法,不过每个同学还是有一定容忍度的。也就是说,队伍中的第i 个同学,最多允许紧跟他身后的Bi 个人先拿到饭菜。一旦在此之后的任意同学比当前同学先拿到饭,当前同学将会十分愤怒。因此,食堂做菜还得照顾到同学们的情绪。 现在,小F 想知道在满足所有人的容忍度这一前提下,自己的学校食堂做完这些菜最少需要多少时间。对于100%的数据,满足1 ≤ N ≤ 1,000,0 ≤ Ti ≤ 1,000,0 ≤ Bi ≤ 7,1 ≤ C ≤ 5。

题解

审题

  题目的要求不是让你求出一个学生的排列,这么理解题意是错误的。正确理解题意是在原来的排列的基础上一个一个同学出队去打饭。

状态的设计

  首先,我们看到0 ≤ Bi ≤ 7,这意味着对于一个人x,如果他开始打饭了,那么[1, x-7]的人肯定都已经打完饭了。所以我们令i=x-7,表示[1, i-1]的人都打完饭这一限制条件。因为食物的美味度与前一个打饭的人有关,所以我们用k表示前一个人打饭相对于i的位置偏右了多少($-8\leq k\leq 7$)。因为同学们的有各自的容忍度,下一个打饭的人的取值范围受到了[i, i+7]内同学的具体状态的影响,所以我们要用S来表示[i, i+7]内同学的具体打饭状态。f表示最短时间。这样,f(i, S, k)就诞生了。

状态的转移

  如果S表示第i位同学打完饭了,那么状态可以转移到f(i + 1, S >> 1, k - 1);否则,从前往后枚举[i, i+7]内没有打饭的人,边枚举边更新可选打饭人的取值范围,因为下一个打饭人要符合他前面所有人的容忍度,而不仅仅是第i个。有Update(f(i, S | (1 << j), j)) with delta(i + k, i + j)。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; //#define Update(x, y) (x) = min((x), (y))
const int MAX_PERSON = 1010, MAX_STATE = 1 << 8, MAX_LAST = 20, INF = 0x3f3f3f3f;
int Dp[MAX_PERSON][MAX_STATE][MAX_LAST];
#define F(i, S, k) Dp[i][S][(k) + 8] void Update(int &x, int y)
{
x = min(x, y);
} struct Person
{
int AfterIdLimit, A;
}_persons[MAX_PERSON];
int TotPerson; int DP()
{
memset(Dp, INF, sizeof(Dp));
F(1, 0, -1) = 0;
for (int i = 1; i <= TotPerson; i++)
for (int S = 0; S <= (1 << 8) - 1; S++)
for (int k = -8; k <= 7; k++)
{
if (F(i, S, k) >= INF)
continue;
_printf("F(%d, %d, %d) = %d\n", i, S, k, F(i, S, k));
if (S & 1)
{
if (k >= -8)
Update(F(i + 1, S >> 1, k - 1), F(i, S, k));
}
else
{
int afterLimit = INF;
for (int j = 0; j <= 7; j++)
{
if (!((S >> j) & 1))
{
if (i + j > afterLimit)
break;
Update(afterLimit, i + j + _persons[i + j].AfterIdLimit);
Update(F(i, S | (1 << j), j), F(i, S, k) + (i + k ? (_persons[i + k].A ^ _persons[i + j].A) : 0));
}
}
}
}
int ans = INF;
for (int k = -8; k <= 0; k++)
Update(ans, F(TotPerson + 1, 0, k));
return ans;
} int main()
{
int caseCnt;
scanf("%d", &caseCnt);
while (caseCnt--)
{
scanf("%d", &TotPerson);
for (int i = 1; i <= TotPerson; i++)
scanf("%d%d", &_persons[i].A, &_persons[i].AfterIdLimit);
printf("%d\n", DP());
}
return 0;
}

  

luogu2157 [SDOI2009]学校食堂 局部状压的更多相关文章

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

    [BZOJ1226][SDOI2009]学校食堂Dining Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满 ...

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

    学校食堂 题目链接:https://www.luogu.org/problem/P2157 数据范围:略. 题解: 发现$B$特别小,很容易想到状压. 即在$dp$的时候弄出来$f_{(i,j,k)} ...

  3. BZOJ1226 SDOI2009学校食堂(状压dp)

    由于Bi<=7,考虑状压. 如果考虑前i个位置的话,状态里需要压入前7个人后7个人,显然是跑不动的. 那么改成考虑前i个人.于是设f[i][j][k]表示前i个人都已吃完饭,i+1后面7个人的吃 ...

  4. BZOJ 1226 [SDOI2009]学校食堂Dining ——状压DP

    看到B<=8,直接状态压缩即可. dp[i][j][k]表示当前相对位置是关于i的,并且i以前的已经就餐完毕,j表示i和之后的就餐情况,k表示上一个就餐的人的相对位置. 然后Dp即可 #incl ...

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

    原题传送门:P2157 [SDOI2009]学校食堂 一看题目就知道是状压dp 设f[i][j][k]表示第1到i-1个人都吃完了饭,第i个人以及后面的7个人是否打饭的状态为j,当前最后打饭的人的编号 ...

  6. BZOJ 1226: [SDOI2009]学校食堂Dining

    1226: [SDOI2009]学校食堂Dining Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 730  Solved: 446[Submit][ ...

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

    Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以 ...

  8. 【bzoj1226】【[SDOI2009]学校食堂Dining】状压dp

    (上不了p站我要死了,侵权度娘背锅) Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人 ...

  9. BZOJ1226 [SDOI2009]学校食堂Dining 【状压dp】

    题目 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示 ...

随机推荐

  1. 软件架构自学笔记-- 转载“虎牙在全球 DNS 秒级生效上的实践”

    虎牙在全球 DNS 秒级生效上的实践 这次分享的是全球 DNS 秒级生效在虎牙的实践,以及由此产生的一些思考,整体上,分为以下 5 各部分: 背景介绍: 方案设计和对比: 高可用: 具体实践和落地: ...

  2. Android视频截图

    本文介绍如何获取视频中某个时间点的数据 调用以下方法即可,特别注意,在获取图片时的参数单位为微秒,不是毫秒 如果错用了毫秒会一直获取第一帧的画面 /** * 获取某个时间点的帧图片 * * @para ...

  3. iOS CoreData 开发之数据模型关系

    接着上一篇,上一篇中,我们简单的实现了一个用户实体,本次添加一个用户信息实体,与用户实体相关联,关系为1:1. 新建一个实体UserInfo:

  4. Android Thermal-engine

    Thermal Engine Thermal 相关的东西主要在Vendor/qcom/proprietary/thermal-engine 目录下: thermal-engine.conf 文件可以用 ...

  5. webstorm中配置过visualsvn,后面做更改要更换authentication realm的解决办法

    找这个找了好久,一直改不过来,终于找到了解决办法 首先,在提交代码时提示: 但是我的authentication realm已经时这个了,并且账号和密码也改了,所以要更改authentication ...

  6. html5——3D转换

    角度旋转 rotateX:默认以center绕x轴旋转 rotateY:默认以center绕y轴旋转 rotateZ:默认以cente绕z轴r旋转 //rotateX原点为center==>正值 ...

  7. JS——offset

    1.offsetWidth.offsetHeight返回盒子宽度和高度,包括padding与border,不包括margin 2.offsetLeft.offsetTop返回盒子距离定位盒子的x轴方向 ...

  8. (转)Struts2访问Servlet的API及......

    http://blog.csdn.net/yerenyuan_pku/article/details/67315598 Struts2访问Servlet的API 前面已经对Struts2的流程已经执行 ...

  9. c#中通过事件实现按下回车跳转控件

    //接受用户输入参数后回车事件 private void tb_KeyPress(object sender, KeyPressEventArgs e) { ) { SendKeys.Send(&qu ...

  10. CAD调用导角命令,并返回导角的圆弧对象

    主要用到函数说明: _DMxDrawX::SendStringToExecuteFun 把命令当着函数执行,可以传参数,详细说明如下: 参数 说明 IDispatch* pParam 命令参数,IMx ...