[ZJOI2005]午餐 (DP)
[ZJOI2005]午餐
題目描述
上午的訓練結束了,THU ACM小組集體去吃午餐,他們一行N人來到了著名的十食堂。這裏有兩個打飯的窗口,每個窗口同一時刻只能給一個人打飯。由於每個人的口味(以及胃口)不同,所以他們要吃的菜各有不同,打飯所要花費的時間是因人而異的。另外每個人吃飯的速度也不盡相同,所以吃飯花費的時間也是可能有所不同的。
THU ACM小組的吃飯計劃是這樣的:先把所有的人分成兩隊,並安排好每隊中各人的排列順序,然後一號隊伍到一號窗口去排隊打飯,二號隊伍到二號窗口去排隊打飯。每個人打完飯後立刻開始吃,所有人都吃完飯後立刻集合去六教地下室進行下午的訓練。
現在給定了每個人的打飯時間和吃飯時間,要求安排一種最佳的分隊和排隊方案使得所有人都吃完飯的時間盡量早。
假設THU ACM小組在時刻0到達十食堂,而且食堂裏面沒有其他吃飯的同學(只有打飯的師傅)。每個人必須而且只能被分在一個隊伍裏。兩個窗口是並行操作互不影響的,而且每個人打飯的時間是和窗口無關的,打完飯之後立刻就開始吃飯,中間沒有延遲。
現在給定N個人各自的打飯時間和吃飯時間,要求輸出最佳方案下所有人吃完飯的時刻。
輸入輸出格式
輸入格式:
第一行一個整數N,代表總共有N個人。
以下N行,每行兩個整數 Ai,Bi。依次代表第i個人的打飯時間和吃飯時間。
輸出格式:
一個整數T,代表所有人吃完飯的最早時刻。
輸入輸出樣例
輸入樣例#1:
5
2 2
7 7
1 3
6 4
8 5
輸出樣例#1:
17
說明
所有輸入數據均為不超過200的正整數。
Solution
首先一個顯而易見的貪心:一個人吃飯的時間越久,為了達成我們的目標,我們要盡量讓他先吃
所以按吃飯時間從大到小排序
首先,我們知道肯定是需要枚舉當前是第幾個人打飯的,但是僅僅這樣不足以確定我們的狀態,所以我們還要確定當前情況下1號窗口和2號窗口分別已經排了多長時間的隊。因此,dp[i][j][k]表示當前處理到第i個人1號窗口排隊時間為j,2號窗口排隊時間為k的最小吃飯時間
if(j>=t[i].a) dp[i][j][k]=min(dp[i][j][k],max(dp[i-1][j-t[i].a][k],j+t[i].b)); //dp[i-1][j-t[i].a][k]表示第i個人排隊和吃飯的時間還不足前i-1個人吃飯的時間,所以沒有造成影響 //後面的j+t[i].b就是造成了影響 if(k>=t[i].a) dp[i][j][k]=min(dp[i][j][k],max(dp[i-1][j][k-t[i].a],k+t[i].b)); //同上
我們發現這個數組會爆內存,怎麽優化呢?
無論是選1號窗口還是2號窗口,前i個人的排隊時間總和是不變的,我們就可以通過j求出k,前綴和就好了
那麽方程就變成了這樣
if(j>=t[i].a) dp[i][j]=min(dp[i][j],max(dp[i-1][j-t[i].a],j+t[i].b));
dp[i][j]=min(dp[i][j],max(dp[i-1][j],sum[i]-j+t[i].b));//sum[i]-j就是k
dp邊界:dp[0][0]=0,其他的都賦為inf就好了,畢竟是要求最小值嘛
Code
#include<bits/stdc++.h>
using namespace std;
const int N=210;
struct node {
int a,b;
bool operator < (const node &c) const{return b>c.b;}
}t[N];
int n,ans;
int sum[N],dp[N][N*N];
int main()
{
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>t[i].a>>t[i].b;
sort(t+1,t+1+n);
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+t[i].a;
memset(dp,0x3f,sizeof(dp)); ans=dp[0][0],dp[0][0]=0;
for(int i=1;i<=n;i++) {
for(int j=0;j<=sum[i];j++) {
if(j>=t[i].a) dp[i][j]=min(dp[i][j],max(dp[i-1][j-t[i].a],j+t[i].b));
dp[i][j]=min(dp[i][j],max(dp[i-1][j],sum[i]-j+t[i].b));
}
}
for(int i=1;i<=sum[n];i++)
ans=min(ans,dp[n][i]);
cout<<ans<<endl;
}
博主蒟蒻,隨意轉載.但必須附上原文鏈接
http://www.cnblogs.com/real-l/
[ZJOI2005]午餐 (DP)