洛谷 P2577 ZJOI2005 午餐

2022-05-08 17:45:06 字數 1078 閱讀 2013

這道題目比較難想。

演算法:貪心+dp

容易想到貪心:吃飯慢的先打飯節約時間, 所以先將人按吃飯時間從大到小排序。

然後就是dp了:

首先,應該想到f[i][j][k]:前i個人,在1號視窗打飯總時間j,在2號視窗打飯總時間k

當然,這樣會爆空間,所以想到去掉一維。

f[i][j]表示前i個人,在1號視窗打飯總時間j,最早吃完飯的時間

我們可以發現 j+k=前i個人打飯總和,k = sum(i)-j。

所以可以維護乙個字首和:

for(int i = 1; i <= n; i++)

sum[i] = sum[i-1] + s[i].a;

接下來就是dp的轉移:

將第i個人放在1號視窗:

if(j>=s[i].a) f[i][j] = min(f[i][j], max(f[i-1][j-s[i].a], j+s[i].b));

f[i-1][j-s[i].a]是i號人打飯+吃飯的時間不足i-1號人吃飯的時間, 所以沒有影響

j+s[i].b就是造成了影響

將第i個人放在2號視窗:

f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+s[i].b));

這裡也是一樣的

(sum[i]-j 就是k)

轉移方程如果沒有看懂,可以結合圖來理解

#includeusing namespace std;

const int n = 210;

int f[n][n*n];

struct node

}s[n];

int sum[n];

int main()

}int ans = 2147483647;

for(int i = 0; i <= sum[n]; i++)

ans = min(ans, f[n][i]);

printf("%d\n", ans);

return 0;

}

洛谷P2577 ZJOI2005 午餐

挺棒的一道dp。貪心策略容易想到。直接按吃飯時間從大到小排序即可。重點是dp。可以設方程為 f 前 i 人 佇列1的時間 j 然後加上乙個常見的滾動陣列套路。方程的轉移還是很有意思。include include include include using namespace std const i...

洛谷 P2577 ZJOI2005 午餐

首先,比較容易想到的一點是應該把所有人按吃飯時間從大到小排個序,讓吃飯時間長的人優先打飯,這樣會是最優的。其次,設f i j k 表示前i個人在一號隊打飯時間為j二號隊打飯時間為k時的總時間的最優解 有點繞 於是乎,轉移方程就是 f i j k min max f i 1 j a i k j b i...

題解 P2577 ZJOI2005 午餐

題目大意 每個人有乙個打飯時間和吃飯時間,求把所有人分到兩個隊伍,所有人都吃完飯的最短時間 動態規劃,貪心 分析 既然每個人有乙個吃飯時間和打飯時間,我們可以大膽猜想,讓吃的慢的人先打飯 我有乙個比較迷的證明,不知道對不對 假如只有乙個佇列,設打飯時間為 a 吃飯時間為 b ans max a j ...