【BZOJ1899】午餐(動態規劃)
阿新 • • 發佈:2018-01-18
需要 記錄 表示 列隊 其中 truct ble read namespace 個人,
第一列隊伍前面所有人打飯的時間和是\(j\)時
最後一個人吃完飯的最小時間
【BZOJ1899】午餐(動態規劃)
題面
BZOJ
題解
我太弱了
這種\(dp\)完全做不動。。
首先,感性理解一些
如果所有人都要早點走,
那麽,吃飯時間長的就先吃
吃飯時間短的就晚點吃
所以,按照吃飯時間排序
我們不難得出一個每個人吃完飯的時間
之和前面所有人的打飯的時間和有關
所以
\(f[i][j][k]\)表示當前做到第\(i\)個人,第一列,第二列前面的人的打飯時間之和分別為\(j,k\)時,最後一個人吃完飯的最小時間
因為人的順序我們是知道的
所以\(j+k\)是一個定值,是所有人打飯時間的前綴和
因此我們只需要記錄其中一個
所以,狀態是\(f[i][j]\)表示當前做到第\(i\)
第一列隊伍前面所有人打飯的時間和是\(j\)時
最後一個人吃完飯的最小時間
如果把這個人放在第一列
\(f[i][j]=min(f[i][j],max(f[i-1][j-Get[i]],j+eat[i]))\)
這個應該不難理解
另外一個,把這個人放在第二列
\(f[i][j]=max(f[i-1][j],sum[i]-j+eat[i])\)
這題應該是一個很顯然的\(dp\)
但是我卻做不出來
我果然太弱了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 210
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if (ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Peo{int a,b;}p[MAX];
int s[MAX],ans=2e9;
int f[MAX][MAX*MAX],n;
bool operator<(Peo a,Peo b)
{
if(a.b!=b.b)return a.b>b.b;
else return a.a>b.a;
}
int main()
{
n=read();
for(int i=1;i<=n;++i)p[i].a=read(),p[i].b=read();
sort(&p[1],&p[n+1]);
for(int i=1;i<=n;++i)s[i]=s[i-1]+p[i].a;
memset(f,63,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;++i)
{
for(int j=s[i-1];j>=0;--j)
{
f[i][j+p[i].a]=min(f[i][j+p[i].a],max(f[i-1][j],j+p[i].a+p[i].b));
f[i][j]=max(f[i-1][j],s[i-1]-j+p[i].a+p[i].b);
}
}
for(int i=0;i<=s[n];++i)ans=min(f[n][i],ans);
printf("%d\n",ans);
return 0;
}
【BZOJ1899】午餐(動態規劃)