luogu P2577午餐 動態規劃

2021-09-19 03:57:29 字數 3273 閱讀 6062

這其實是乙個揹包問題的變形,如果只有乙個視窗的話,對於排隊打飯的時間是固定的,那麼只要按照誰吃的慢誰先上就可以得出最優值。

這道題有兩個視窗,貪心的方法還是一樣的,但是需要考慮分配問題。

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