洛谷 P2157 [SDOI2009]学校食堂

洛谷传送门

JDOJ 1924: [SDOI2009]学校食堂Dining

JDOJ传送门

Description

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

Input

第一行包含一个正整数C,表示测试点的数据组数。 每组数据的第一行包含一个正整数N,表示同学数。 每组数据的第二行起共N行,每行包含两个用空格分隔的非负整数Ti和Bi,表示按队伍顺序从前往后的每个同学所需的菜的口味和这个同学的忍受度。 每组数据之间没有多余空行。

Output

包含C行,每行一个整数,表示对应数据中食堂完成所有菜所需的最少时间。

Sample Input

2 5 5 2 4 1 12 0 3 3 2 2 2 5 0 4 0

Sample Output

16 1

HINT

对于第一组数据:

同学1允许同学2或同学3在他之前拿到菜;同学2允许同学3在他之前拿到菜;同学3比较小气,他必须比他后面的同学先拿菜……

一种最优的方案是按同学3、同学2、同学1、同学4、同学5做菜,每道菜所需的时间分别是0、8、1、6及1。

【数据规模和约定】

对于30%的数据,满足1 ≤ N ≤ 20。

对于100%的数据,满足1 ≤ N ≤ 1,000,0 ≤ Ti ≤ 1,000,0 ≤ Bi ≤ 7,1 ≤ C ≤ 5。

存在30%的数据,满足0 ≤ Bi ≤ 1。

存在65%的数据,满足0 ≤ Bi ≤ 5。

存在45%的数据,满足0 ≤ Ti ≤ 130。

题解:

2019.11.6模拟赛T1 爆蛋场

因为蒟蒻对状压不是很熟悉,所以一开始根本没往那边想,发现可以暴力生成全排列看看合不合法。然后持续更新答案。预计30\(pts\)但是写挂了

那么讲一下这个正解。(因为蒟蒻才学状压,所以很多地方都有初学者的痕迹,请大佬们海涵)

一开始迟迟无法理解这道题为啥能用\(DP\),因为这道题对于每一个人来讲,他什么时候打饭既和他前面的人有关(能不能容忍他打饭),也跟后面的人有关(他能不能容忍他们打饭)。在我的印象中,这就叫后效性,是不符合\(DP\)的条件的。

所以需要用状态压缩解决

是的,状态压缩就是把状态化成二进制数存进数组中,然后保证当前状态下转移时是无后效性的。(多么妙啊)

那么我们考虑状态的设计思路:

首先,这个东西是一定要与枚举到的人有关的,所以开一维存当前枚举到哪个人。

其次,因为这个东西的转移边界是容忍后面的人吃没吃饭。那么就会有一维存状态:表示\(i\)和\(i\)后面\(7\)个人到底吃没吃饭。

最后,因为这个转移还和前面的人能不能忍你先吃饭有关。所以还需要开一维维护这个关系,存储上一个打饭的人到当前这个人的相对距离。

综上,设置:

\(dp[i][st][k]\)为:当第\(1\)到第\(i-1\)个人全部吃完饭后,\(i\)后\(7\)个人(把\(i\)也算上)吃没吃饭,\(i\)前面吃饭的人和\(i\)之间相对距离为\(k\)时的最小价值。(设\(0\)为没吃过,\(1\)为吃过)

那么答案就应该是\(\min\{dp[n+1][0][k]\}\quad (k\in[0,8])\)。这里的\(k\)的取值是因为数组不能开负数,所以把整个\(k\)的区间从\([-8,0]\)挪到\([0,8]\)了。

然后我们考虑怎么去转移。

注意:这里的状态(是以十进制存储的)拆成二进制(有8位)后,最后面那位表示的不是最后的那个人,恰恰相反,是第一个人(即当前的那个\(i\)))

可以想到的是,对于每一个人,状态转移首先需要看这个人到底吃没吃,那么我们分两种情况讨论:

第一种:这个\(i\)已经吃了。这种情况下,\(st\&1\)应该为真。那么就可以直接去推下一个人,转移方程为:

\[dp[i+1][j>>1][k+7]=\min(dp[i+1][j>>1][k+7],dp[i][j][k+8]);
\]

第二种:这个\(i\)还没有吃。这种情况下,是没有办法转移到\(i+1\)的,因为我们的状态设置的是前面的人都已经打完饭了(以排除后效性)。所以我们就要枚举状态来选择后面的7个人(当然包括自己)谁先打饭。

但是,这里需要细考虑一下:不是后面的7个人中的所有人都是可以打饭的。就比如后面的第\(7\)个人,如果后面的第一个人的忍耐度很小,一点都不能容忍自己后面的人先打,那么这个第\(7\)人就是选不了的。(没办法摊上暴躁同学就这样)

所以我们还需要在枚举的同时判断是否合法。

开一个变量\(limit\)储存目前可行的最大范围,随着枚举的继续,这个范围要么不动,要么缩小。所以如果当前枚举到的人超过了这个范围,那么他之后的所有人也都超出了这个范围,直接\(break\)掉就好。

这个时候的转移方程是:

\[dp[i][j|(1<<h)][h+8]=\min(dp[i][j|(1<<h)][h+8],dp[i][j][k+8]+val[now])
\]

其中\(val[now]\)表示做这道菜的需要的时间。

(这里还有个性质:a|b-a&b==a^b)

所以就得出了完整的思路。

以及完整的代码:

#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
#define min(a,b) a<b?a:b
int n,ans,limit;
int t[1010],b[1010];
int dp[1010][1<<8][20];
//dp[i][st][k]表示当前为i人、其后状态为st、
//前一个吃饭的人离i距离为k时需要的最少时间。
//即上一个吃饭的人为i+k-8
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
int x=0,f=1;
char ch=nc();
while(ch<48){if(ch=='-')f=-1;ch=nc();}
while(ch>47) x=(((x<<2)+x)<<1)+ch-48,ch=nc();
return x*f;
}
int main()
{
int T;
T=read();
while(T--)
{
n=read();
for(int i=1;i<=n;i++)
t[i]=read(),b[i]=read();
memset(dp,INF,sizeof(dp));
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)
{
if(j&1)
dp[i+1][j>>1][k+7]=min(dp[i+1][j>>1][k+7],dp[i][j][k+8]);
else
{
limit=INF;
for(int h=0;h<=7;h++)
if(!((j>>h)&1))
{
if(i+h>limit)
break;
limit=min(limit,i+h+b[i+h]);
dp[i][j|(1<<h)][h+8]=min(dp[i][j|(1<<h)][h+8],dp[i][j][k+8]+(i+k?(t[i+k]^t[i+h]):0));
}
}
}
ans=INF;
for(int k=0;k<=8;k++)
ans=min(ans,dp[n+1][0][k]);
printf("%d\n",ans);
}
return 0;
}

SDOI 2009 学校食堂的更多相关文章

  1. SDOI 2009 学校食堂 状压dp

    这个题的关键处1 紧跟着他的bi个人 —— 由此得出任意一个状态都可以表示为 有第一个人没吃到饭做分隔的前面所有人已吃饭,并用1<<8表示之后的(包括他)的八个人的状态2 信息仍然是上一个 ...

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

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

  3. BZOJ-1226 学校食堂Dining 状态压缩DP

    1226: [SDOI2009]学校食堂Dining Time Limit: 10 Sec Memory Limit: 259 MB Submit: 588 Solved: 360 [Submit][ ...

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

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

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

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

  6. [SDOI2009]学校食堂Dining

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

  7. 【SDOI2009】学校食堂

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

  8. P2157 [SDOI2009]学校食堂

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

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

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

随机推荐

  1. Java 的synchronized关键字使用

    synchronized 关键字是实现锁的一种方式,是在jvm层面实现的非公平锁,以下是使用synchronized的四种方式 synchronized 特性: 1.非公平锁 2.可重入性 1.作用在 ...

  2. CF53E Dead Ends

    CF53E Dead Ends 洛谷评测传送门 题目描述 Life in Bertown has become hard. The city has too many roads and the go ...

  3. LG5202 「USACO2019JAN」Redistricting 动态规划+堆/单调队列优化

    问题描述 LG5202 题解 \[opt[i]=xx+(cnt[i]-cnt[yy]<=0)\] 发现\(cnt[i]-cnt[yy] <= 0\)只能有两种取值 于是直接堆优化即可 \( ...

  4. console调试技巧

    1.console.log() 我们经常会使用console.log来打印出某个变量的值或者某个实体对象,也可以传入多个变量参数,它会按照传入顺序进行打印: 1. 传入一个变量 const a = 1 ...

  5. git必知必会

    1. Git 配置 --system #系统级别--global #用户全局--local #单独一个项目 git config --global user.name "xxxx" ...

  6. js判断浏览器是否安装或启用了flash的方法总结

    目录 # js判断浏览器是否安装或启用了flash的方法 # chrome浏览器启用flash插件的方法 # 参考 # js判断浏览器是否安装或启用了flash的方法 在传统浏览器,可以使用windo ...

  7. RMAN详细教程(三):备份脚本的组件和注释

    RMAN详细教程(一):基本命令代码 RMAN详细教程(二):备份.检查.维护.恢复 RMAN详细教程(三):备份脚本的组件和注释 RMAN详细教程(四):备份脚本实战操作 一.基本组件: 1.Ser ...

  8. centos6和centos7的防火墙基本命令

    一.centos6: 1.firewall的基本启动/停止/重启命令 $查看防火墙状态: service iptables status (/etc/init.d/iptables status) $ ...

  9. PHP 7.4.0 发布

    近日,PHP 7.4.0 发布了,此版本标志着 PHP 7 系列的第四次特性更新. PHP 7.4.0 进行了许多改进,并带来了一些新特性,包括: Typed Properties  类型属性 类属性 ...

  10. java 类内部定义接口

    java类内部可以定义接口,作用可以看作是对类功能的进一步补充,类里面包含两部分:一部分是自己的固定的,一部分是可以变化的,而这可变的部分就编程了一个接口. 另一个作用是避免命名冲突. 示例 类Fru ...