題解 P2577 ZJOI2005 午餐

2022-05-07 21:39:11 字數 1099 閱讀 3951

題目大意:每個人有乙個打飯時間和吃飯時間,求把所有人分到兩個隊伍,所有人都吃完飯的最短時間

動態規劃,貪心

分析:既然每個人有乙個吃飯時間和打飯時間,我們可以大膽猜想,讓吃的慢的人先打飯

我有乙個比較迷的證明,不知道對不對……

假如只有乙個佇列,設打飯時間為\(a\),吃飯時間為\(b\)

\(ans = max\^a_j+b_i \quad | \quad 1 \in [1,n]\}\)

假如有兩個人編號\(1\),\(2\)

第一種情況:\(ans_1 = max\=a_1+a_2+b_2\)

第二種情況:\(ans_2 = max\ = a_1 + a_2 + b_1\)

假如第一種情況更優:\(ans_1 < ans_2 \implies b_2 < b_1\)

所以我們按照\(b\)值降序排列可以使答案最優,然後我們考慮\(dp\)

設\(f[i][j][k]\)表示前\(i\)個人,第\(1\)個佇列的打飯時間之和為\(j\),第\(2\)個佇列的打飯時間為\(k\)的最優答案,轉移顯然,陣列會爆

我們發現第\(3\)維可以略去,因為我們知道\(\sum_1^ia_i\),以及第乙個佇列的\(\sum a\),我們就可以算出第二個佇列的\(\sum a\),這個有點像方格取數的優化

然後\(f[i][j] = \begin max \ \quad j \geq a_i \\ max\^ia_j-j+b_i\} \end\)

#include #include #include using namespace std;

const int maxn = 201;

struct person

}person[maxn];

int n,ans = 0x7fffffff,sum,f[maxn][40001];

int main()

} for(int i = 0;i <= sum;i++)ans = min(ans,f[n][i]);

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

return 0;

}

洛谷 P2577 ZJOI2005 午餐

這道題目比較難想。演算法 貪心 dp 容易想到貪心 吃飯慢的先打飯節約時間,所以先將人按吃飯時間從大到小排序。然後就是dp了 首先,應該想到f i j k 前i個人,在1號視窗打飯總時間j,在2號視窗打飯總時間k 當然,這樣會爆空間,所以想到去掉一維。f i j 表示前i個人,在1號視窗打飯總時間j...

洛谷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...