洛谷 P2577 [ZJOI2005]午餐【貪心】【dp】


題目:

傳送門


題意:

一共有nn個人,每個人都有兩個信息:打飯時間和喫飯時間
現在有兩個窗口可以打飯,問最短多快能使所有人都喫完飯


分析:

假如我們現在已經確定了兩個窗口分別有哪些人,那麼要想使得總時間最短,我們就應該把喫得慢的人儘可能的往前安排
這樣我們要考慮的就是如何安排這兩個窗口的人,設fi,j,kf_{i,j,k}表示前ii個人中,在第一個窗口的排隊時間爲jj,第二個窗口的排隊時間爲kk時最短耗時
但這樣明顯是要MLEMLE的,所以我們必須要省掉一維空間,我們發現j+kj+k的值在每個ii的時候都是固定的,這樣的話我們就可以用前綴和維護每個j+kj+k的值,留下一個jj,而kksijs_i-j表示
方程呢,我們就考慮當前的fi,jf_{i,j}會由什麼轉移過來,一個是前面i1i-1這些人耗得時間會比第ii個人的總耗時都要多,這樣我們就直接由fi1,jaf_{i-1,j-a}轉移;另一個當現在是喫得最慢的了,那沒辦法,總時間就是排隊等待的時間加上第ii個人喫飯的時間
fi,j=max(fi1,ja,j+b)f_{i,j}=max(f_{i-1,j-a},j+b)
當然,這只是第ii個人在一號窗口排隊的情況,還有在二號窗口的也是同理


代碼:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<cmath>
#include<vector>
#define LL long long 
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
struct node{
	int a,b;
}x[205];
bool cmp(node a,node b) {return a.b>b.b;}
int sum[205];
int f[205][40005];
int main()
{
	int n=read();
	for(int i=1;i<=n;i++) x[i].a=read(),x[i].b=read();
	sort(x+1,x+1+n,cmp);
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+x[i].a;
	for(int i=0;i<=n;i++)
	  for(int j=0;j<=sum[n];j++)
	    f[i][j]=99999999;
	f[0][0]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=x[i].a;j<=sum[i];j++) f[i][j]=min(f[i][j],max(f[i-1][j-x[i].a],j+x[i].b));
		for(int j=0;j<=sum[i];j++) f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+x[i].b));
	}
	int ans=2147483647;
	for(int i=0;i<=sum[n];i++) ans=min(ans,f[n][i]);
	cout<<ans;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章