点此看题面

大致题意: 有\(N\)个学生去食堂打饭,每个学生有两个属性:打饭时间\(a_i\)和吃饭时间\(b_i\)。现要求将这些学生分成两队分别打饭,求最早何时所有人吃完饭。

贪心

首先,依据贪心的思想,肯定是吃饭时间长的先打饭,因此可以将其按吃饭时间先排序预处理一遍。

如何\(DP\)

贪心完,就是\(DP\)了。

个人认为三维\(DP\)还是非常好想的:用\(f_{i,j,k}\)表示当前轮到第\(i\)个学生、在两个窗口打饭分别用了\(j\)和\(k\)个单位时间时最早吃完的时间

其实,确定了\(i\)和\(j\),此时可以唯一确定\(k=sum_i-j\)(\(sum_i=\sum_{x=1}^ia_x\)),故可以将原\(DP\)删去一维,变成二维\(DP\)。

关于状态转移

状态转移应该也是挺容易想到的,可以分将第\(i\)个学生放在\(1\)号窗口还是\(2\)号窗口讨论。

  • 放在\(1\)号窗口:此时的时间为\(max(f_{i-1,j-a_i},j+b_i)\)。
  • 放在\(2\)号窗口:此时的时间为\(max(f_{i-1,j},sum_i-j+b_i)\)。

大致思路就是如此。

代码

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define uint unsigned int
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define abs(x) ((x)<0?-(x):(x))
#define INF 1e9
#define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
#define ten(x) (((x)<<3)+((x)<<1))
#define N 200
using namespace std;
int n,sum[N+5];
struct student
{
int x,y;
inline bool operator < (const student Cmp) const
{
return y>Cmp.y;
}
}s[N+5];
class FIO
{
private:
#define Fsize 100000
#define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];
public:
FIO() {FinNow=FinEnd=Fin;}
inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=ten(x)+(ch&15),isdigit(ch=tc()));x*=f;}
inline void read_char(char &x) {while(isspace(x=tc()));}
inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;}
inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
inline void write_char(char x) {pc(x);}
inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
inline void end() {fwrite(Fout,1,FoutSize,stdout);}
}F;
class Class_DP
{
private:
int f[N+5][N*N+5];
public:
inline int GetAns()
{
register int i,j,ans=INF;
for(i=1;i<=n;++i)
{
for(j=0;j<=sum[i];++j) f[i][j]=min(sum[i]-j>=s[i].x?max(f[i-1][j],(sum[i]-j)+s[i].y):INF,j>=s[i].x?max(f[i-1][j-s[i].x],j+s[i].y):INF);//分两种情况讨论并转移
for(;j<=sum[n];++j) f[i][j]=INF;//对不可能出现的情况直接赋值为INF
}
for(i=0;i<=sum[n];++i) ans=min(ans,f[n][i]);//取min
return ans;
}
}DP;
int main()
{
register int i;
for(F.read(n),i=1;i<=n;++i) F.read(s[i].x),F.read(s[i].y);
for(sort(s+1,s+n+1),i=1;i<=n;++i) sum[i]=sum[i-1]+s[i].x;//贪心的思想,将原数组排序,然后求出前缀和
return F.write(DP.GetAns()),F.end(),0;
}

【洛谷2577】[ZJOI2005] 午餐(较水DP)的更多相关文章

  1. BZOJ1899或洛谷2577 [ZJOI2005]午餐

    BZOJ原题链接 洛谷原题链接 解决这题得先想到一个贪心:吃饭慢的先排队. 并不会证明(感觉显然 设\(f[i][j][k]\)表示已经排好了前\(i\)人,第一个队伍需要花费的打饭时间为\(j\), ...

  2. 洛谷 2577 [ZJOI2005]午餐——序列dp

    题目:https://www.luogu.org/problemnew/show/P2577 可以从只有一个窗口的角度思考出一个贪心结论.就是应当按吃饭时间(不算打饭时间)从大到小排序.这样交换相邻两 ...

  3. 洛谷P2577 [ZJOI2005]午餐 打饭时间作为容量DP

    P2577 [ZJOI2005]午餐 )逼着自己做DP 题意: 有n个人打饭,每个人都有打饭时间和吃饭时间.有两个打饭窗口,问如何安排可以使得总用时最少. 思路: 1)可以发现吃饭时间最长的要先打饭. ...

  4. 【题解】洛谷P2577 [ZJOI2005] 午餐(DP+贪心)

    次元传送门:洛谷P2577 思路 首先贪心是必须的 我们能感性地理解出吃饭慢的必须先吃饭(结合一下生活) 因此我们可以先按吃饭时间从大到小排序 然后就能自然地想到用f[i][j][k]表示前i个人在第 ...

  5. [洛谷P2577] [ZJOI2005]午餐

    洛谷题目链接:[ZJOI2005]午餐 题目描述 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的 ...

  6. 洛谷P2577 [ZJOI2005]午餐 dp

    正解:序列dp 解题报告: 传送门! 这题首先要想到一个显然的贪心:每个窗口的排队顺序都是按照吃饭时间从大到小排序的 证明如下: 这种贪心通常都是用微扰法,这题也不例外 现在假如已经确定了每个窗口有哪 ...

  7. 洛谷 P2577 [ZJOI2005]午餐

    这道题目比较难想. 题解: 算法:贪心+dp 容易想到贪心:吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序. 然后就是dp了: 首先,应该想到f[i][j][k]:前i个人,在1号窗口打饭 ...

  8. 洛谷 P2577 [ZJOI2005]午餐 题解

    每日一题 day56 打卡 Analysis 算法:贪心+dp 容易想到贪心:吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序. 然后就是dp了: 首先,应该想到f[i][j][k]:前i个 ...

  9. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

  10. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

随机推荐

  1. Codeforces Round #558 (Div. 2)B(SET,模拟)

    #include<bits/stdc++.h>using namespace std;int a[100007];int cnt[100007];int main(){    int n; ...

  2. spring boot jpa 使用<S extends T> List<S> findAll(Example<S> example)查询数据

    直接上代码 //查询条件对象 TinventivePrinciple time = new TinventivePrinciple(); //设置需要查询的条件(赋值) time.setIsTime( ...

  3. Java实例——基于jsoup的简单爬虫实现(从智联获取工作信息)

    这几天在学习Java解析xml,突然想到Dom能不能解析html,结果试了半天行不通,然后就去查了一些资料,发现很多人都在用Jsoup解析html文件,然后研究了一下,写了一个简单的实例,感觉还有很多 ...

  4. 利用CSS制作脸书

    很多网站都支持图片上的头像框识别,鼠标在头像框处,会提示一些人物信息. 这次就利用CSS实现这样一个功能: div处主要包括两部分,一部分是图片:另一部分是链接以及脸框 <div class=& ...

  5. k8s集群新增节点

    节点为centos7.4 一.node节点基本环境配置 1.配置主机名 2.配置hosts文件(master和node相互解析) 3.时间同步 ntpdate pool.ntp.org date ec ...

  6. c#之 quartz的学习

    目录: 一. Quartz的API 二.Trigger 的使用 三.使用 JobDataMap 来往Job中传值 四. Calendars 五.SimpleTrigger 六.CronTrigger ...

  7. thinkphp5.1常量定义使用

    thinkphp5.1取消了系统常量 可以把常量配置在app.php文件中 //配置网站地址 'WEB_URL'=>'http://127.0.0.1/tp5', 可以使用config()函数直 ...

  8. 阿里云服务器 linux 怎么安装php(PHPSTUDY)开发环境

    1.首先登录行云管家(https://yun.cloudbility.com/login.html) wget -c http://lamp.phpstudy.NET/phpstudy.bin //下 ...

  9. Django - 回顾(1)- 模型层的Meta选项详解

    一.模型层的Meta选项详解 Django模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.使用方法及参数解释如下: class Book(models.Model): nid ...

  10. Shell变量赋值语句不能有空格

    a = 1是错的!!!!!只有 a=1才是正确的.