刷题记录【ZJOJ2005午餐】,贪心+DP或者
https://www.luogu.org/problemnew/show/P2577
题目描述
上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。
THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。
现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。
假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。
现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。
输入输出格式
输入格式:
第一行一个整数N,代表总共有N个人。
以下N行,每行两个整数 Ai,Bi。依次代表第i个人的打饭时间和吃饭时间。
输出格式:
一个整数T,代表所有人吃完饭的最早时刻
这题数据范围比较小,适合采用模拟退火算法,于是先写一发模拟退火算法AC掉
//模拟退火乱搞
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
struct per{
int wait,eat;
bool operator < (const per b)const
{
return eat>b.eat;
}
}q[505];
int n,ans=0x7f7f7f7f;
int q1[505],q2[505],t1,t2;
void update()
{
int sum = 0,ans1=0,ans2=0;
for(int i = 1; i <= t1; i ++)
{
sum+=q[q1[i]].wait;
ans1 = max(ans1,sum+q[q1[i]].eat);
}
sum = 0;
for(int i = 1; i <= t2; i ++)
{
sum+=q[q2[i]].wait;
ans2 = max(ans2,sum+q[q2[i]].eat);
}
ans = min(ans,max(ans1,ans2));
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n ; i ++)
{
scanf("%d%d",&q[i].wait,&q[i].eat);
}
sort(q+1,q+1+n);
int ansn = 0;
for(int i = 1; i <= n ; i ++)
{
if(i&1)q1[++t1]=i;
else q2[++t2]=i;
}
update();
srand(23333);
for(int j = 1; j <= 30000; j ++)
{
t1=t2=0;
for(int i = 1; i <= n ; i ++)
{
if(!rand()%i)
{
if(i&1)q1[++t1]=i;
else q2[++t2]=i;
}
else
{
if(rand()&1)q1[++t1]=i;
else q2[++t2]=i;
}
}
update();
}
cout<<ans;
}
下面是正解DP
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct per{
int wait,eat;
bool operator < (const per b)const
{
return eat>b.eat;
}
}q[505];
int n,sum[505],f[505][40006];
int main()
{
scanf("%d",&n);
for(int i = 1 ; i<= n ; i++)
{
scanf("%d%d",&q[i].wait,&q[i].eat);
}
memset(f,0x3f,sizeof(f));
f[0][0]=0;
sort(q+1,q+1+n);
for(int i = 1; i <= n; i ++)
sum[i]=sum[i-1]+q[i].wait;
for(int i = 1; i <= n; i ++)
for(int j = 0; j <= sum[i-1];j ++)
if(f[i-1][j]!=0x3f3f3f3f)
{
f[i][j+q[i].wait]=min(f[i][j+q[i].wait],max(f[i-1][j],j+q[i].wait+q[i].eat));
f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+q[i].eat));
}
int ans = 0x7f7f7f7f;
for(int i = 0; i<= sum[n]; i ++)
ans = min(f[n][i],ans);
printf("%d",ans);
}