這道題目比較難想。
演算法:貪心+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 ...