刷題記錄【ZJOJ2005午餐】,貪心+DP或者
阿新 • • 發佈:2018-12-26
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);
}