link
description
tar把一段凹凸不平的路分成了高度不同的n段,並用h[i]表示第i段高度。現在tar一共有n種泥土可用,它們都能覆蓋給定的連續的k個部分。對於第i種泥土,它的**為c[i],可以使得區間[i,min(n,i+k-1)] 的路段的高度增加e[i]。tar要設定一種泥土使用計畫,使得使用若干泥土後,這條路最低的高度盡量高,並且這個計畫必須滿足以下兩點要求:
(1)每種泥土只能使用一次。
(2)泥土使用成本必須小於等於m。
請求出這個最低的高度最高是多少。
solution
30分
事實上,資料是允許拿到90分的,我們直接跑一次遞迴就可以了,記錄最低值的最高值
100分
這個的狀壓dp很巧妙,從來沒做過這種不需要存所有狀態的狀壓dp
從「最低的高度最高」就可以看出,這道題是用二分的,正解就是二分答案。
從而,我們就把這道題目變為一道判定性的問題,給出乙個mid,問你是否符合上面的題意。
普通方法使用遞迴判斷可行性
既然可以用遞迴,那麼顯然可以用動態規劃。
我們設f[i,s]表示你當前想選第i種泥土,前面k種的狀態(包括i)是什麼,用二進位制表示,,0表示在那個位置沒用了泥土,1表示用了。(用沒用表示從他開始往後鋪,專屬於他的泥土)一定要看下面第二個圖
我們用當前f[i,s]去更新f[i+1,s1]
關鍵是我們怎麼轉移。
對於每一種泥土,只有選和不選兩種狀態,那麼我們只要考慮這兩種情況就可以了
在此之前,我們先看乙個東西
注意,我們這裡是用i,更新i+1
讀圖可以發現,對i+1有影響的只有從i前k-1個(包括i)
可以發現,只有i包括i的前k-1個對i+1是有影響的。
因為你選到i時,狀態是s,那麼,如果從i更新到i+1,狀態就是s去掉最後一位,也就是(s>>1),其實就是s/2
我們統計s狀態中,有哪個地方是選了泥土的,然後記錄一下,他們一共會讓i+1這個位置的土地高多少,設這個數為num,要多看圖,多寫草稿
為什麼呢,因為前面的加了對應的e陣列的某乙個值,又因為它會影響到當前這個位置,看上圖,所以,我們要看看,他們究竟影響到i+1這個位置增加多少值,所以我們要提前記錄下來
其中s是列舉的!列舉的!列舉的!
①不選如果不選,那麼num+h[i]必定是大於等於mid的,這樣才符合題目要求,如果不懂反覆讀上面的那句話,看看我畫出來精美的圖,就知道了。不懂都會懂
滿足的上面的情況,我們就可以轉移了
f[i+1,s>>1]:=min(f[i+1,s>>1],f[i,s])
②選如果選,就要滿足num+h[i]+e[i]是大於等於mid的,同理也是上面所說
那麼當前的位置s狀態中i+1的位置應該是1,所以,我們就是要更新新的s
f[i+1,s>>1 or 1 shl (k-1)]:=min(f[i+1,s>>1 or 1 shl (k-1)],f[i,j]+c[i]);
最後答案的判斷就是判斷有沒有乙個被更改過值得f[n,i](i是狀態)是小於等於m的,因為在前面的操作中,都保證了更新過的f陣列是符合題目要求的
這道題充分的體現了動態規劃的屌
code
uses math;varn,m,k,i,j,l,r,mid:longint;
a,b,c:
array[0..100] of
longint;
f:array[0..100,0..2047] of
longint;
function
pd(x:longint):boolean;
vari,j,jj,num:longint;
begin
fillchar(f,sizeof(f),
255);
f[0,0]:=0
;
for i:=0
to n-1
dobegin
for j:=0
to1 shl k-1
doif f[i,j]<>-1
then
begin
num:=0
;
for jj:=k-1
downto1do
if (1 shl(jj)) and j<>0
then
inc(num,b[i-(k-jj-1
)]);
if num+a[i+1]>=x then
if f[i+1,j shr 1]<>-1
then
f[i+1,j shr 1]:=min(f[i+1,j shr 1
],f[i,j])
else
f[i+1,j shr 1]:=f[i,j];
if num+a[i+1]+b[i+1]>=x then
if f[i+1,j shr 1+1 shl (k-1)]<>-1
then
f[i+1,j shr 1+1 shl (k-1)]:=min(f[i+1,j shr 1+1 shl (k-1)],f[i,j]+c[i+1
])
else
f[i+1,j shr 1+1 shl (k-1)]:=f[i,j]+c[i+1
];
end;
end;
for i:=0
to1 shl k-1
doif f[n,i]<>-1
then
if f[n,i]<=m then
exit(true);
exit(false);
end;
begin
assign(input,
'cover.in
');reset(input);
assign(output,
'cover.out
');rewrite(output);
readln(n,m,k);
for i:=1
to n do
readln(a[i],b[i],c[i]);
l:=1
; r:=maxlongint-1
;
while l<=r do
begin
mid:=(l+r) shr 1
;
if pd(mid) then
l:=mid+1
else
r:=mid-1
;
end;
writeln(l-1
);end.
jzoj3521 道路覆蓋 二分 狀壓dp
description ar把一段凹凸不平的路分成了高度不同的n段,並用h i 表示第i段高度。現在tar一共有n種泥土可用,它們都能覆蓋給定的連續的k個部分。對於第i種泥土,它的 為c i 可以使得區間 i,min n,i k 1 的路段的高度增加e i tar要設定一種泥土使用計畫,使得使用若干...
Jzoj4729 道路修建
給你乙個聯通無向圖,問你要修建幾條邊使得該圖是乙個邊雙連通圖 無比經典,肯定是乙個tarjan求橋,刪掉後縮點,變成一顆樹,看看有幾個葉子結點,葉子結點一對對連起來即可 include include include include using namespace std struct edge g...
JZOJ 1244 修建道路
description farmer john最近得到了一些新的農場,他想新修一些道路使得他的所有農場可以經過原有的或是新修的道路互達 也就是說,從任乙個農場都可以經過一些首尾相連道路到達剩下的所有農場 有些農場之間原本就有道路相連。所有n 1 n 1,000 個農場 用1.n順次編號 在地圖上都表...