這其實是乙個揹包問題的變形,如果只有乙個視窗的話,對於排隊打飯的時間是固定的,那麼只要按照誰吃的慢誰先上就可以得出最優值。
這道題有兩個視窗,貪心的方法還是一樣的,但是需要考慮分配問題。
設dp[i][j][k]
: 下標:前i個人在視窗1花了j的打飯時間,在視窗2花了k的打飯時間。值: 前i個人最小的用餐時間。
設打飯時間為a
,吃飯時間為b
。
狀態轉移方程很容易寫出來:
考慮決策:
第i個人打飯+吃飯的時間被前i-1個人的總時間覆蓋。
第i個人打飯+吃飯的時間不被前i-1個人的總時間覆蓋。
在視窗1打飯
d p[
i][j
][k]
=min
(dp[
i][j
][k]
,max
(dp[
i−1]
[j−a
][k]
,j+b
))
dp[i][j][k] = min(dp[i][j][k], max(dp[i-1][j-a][k], j+b) )
dp[i][
j][k
]=mi
n(dp
[i][
j][k
],ma
x(dp
[i−1
][j−
a][k
],j+
b))
在視窗2打飯
d p[
i][j
][k]
=min
(dp[
i][j
][k]
,max
(dp[
i−1]
[j][
k−a]
,j+b
))
dp[i][j][k] = min(dp[i][j][k], max(dp[i-1][j][k-a], j+b) )
dp[i][
j][k
]=mi
n(dp
[i][
j][k
],ma
x(dp
[i−1
][j]
[k−a
],j+
b))
但由於資料量是200*40000*40000
,所以三維開不下。
對於這種兩個有關聯的變數,就要考慮用乙個變數推出另乙個變數。
注意前面乙個隊伍的情況,打飯時間是固定的!
所以對於前i個人的打飯時間是固定的!那麼只要知道花在視窗1多少打飯時間,自然就可以知道花在視窗2的打飯時間了。
因此便省去了一維。
設dp[i][j]
: 下標:前i個人在視窗1花了j的打飯時間。值: 前i個人最小的用餐時間。
狀態轉移方程:
在視窗1打飯
d p[
i][j
]=mi
n(dp
[i][
j],m
ax(d
p[i−
1][j
−a],
j+b)
)dp[i][j] = min(dp[i][j], max(dp[i-1][j-a],j+b))
dp[i][
j]=m
in(d
p[i]
[j],
max(
dp[i
−1][
j−a]
,j+b
))在視窗2打飯
sum[i]:
前i個人打飯時間的字首和。
sum[i]-j:
前i個人在隊伍2的打飯時間。
d p[
i][j
]=mi
n(dp
[i][
j],m
ax(d
p[i−
1][j
],su
m[i]
−j+b
))
dp[i][j] = min(dp[i][j], max(dp[i-1][j], sum[i]-j+b))
dp[i][
j]=m
in(d
p[i]
[j],
max(
dp[i
−1][
j],s
um[i
]−j+
b))
#include
using
namespace std;
#define for0(a,b) for(int i = a; i < b; ++i)
#define fore(a,b) for(int i = a; i <= b; ++i)
typedef
long
long ll;
typedef pair<
int,
int> pii;
const
int maxn =
200+5;
const
int inf =
0x3f3f3f3f
;struct peo
}a[maxn]
;int dp[maxn]
[maxn*maxn]
,n, sum[maxn]
;// 前i個人,在隊伍1打飯耗時j 時總的最小用餐時間
intmain()
sort
(a+1
,a+1
+n);
memset
(dp, inf,
sizeof dp)
; dp[0]
[0]=
0;for(
int i =
1; i <= n;
++i)
sum[i]
= sum[i-1]
+a[i]
.da;
for(
int i =
1; i <= n;
++i)
}int ans = inf;
for(
int i =
0; i <= sum[n]
;++i)
if(dp[n]
[i]< ans) ans = dp[n]
[i];
printf
("%d\n"
, ans)
;return0;
}
題解 P2577 ZJOI2005 午餐
題目大意 每個人有乙個打飯時間和吃飯時間,求把所有人分到兩個隊伍,所有人都吃完飯的最短時間 動態規劃,貪心 分析 既然每個人有乙個吃飯時間和打飯時間,我們可以大膽猜想,讓吃的慢的人先打飯 我有乙個比較迷的證明,不知道對不對 假如只有乙個佇列,設打飯時間為 a 吃飯時間為 b ans max a j ...
洛谷 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...