狀壓DP NOIPTG2005過河

2021-07-27 23:57:08 字數 1841 閱讀 2094

先上題:洛谷1052

題目描述

在河上有一座獨木橋,乙隻青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點:0,1,……,l(其中l是橋的長度)。座標為0的點表示橋的起點,座標為l的點表示橋的終點。青蛙從橋的起點開始,不停的向終點方向跳躍。一次跳躍的距離是s到t之間的任意正整數(包括s,t)。當青蛙跳到或跳過座標為l的點時,就算青蛙已經跳出了獨木橋。

題目給出獨木橋的長度l,青蛙跳躍的距離範圍s,t,橋上石子的位置。你的任務是確定青蛙要想過河,最少需要踩到的石子數。

輸入

輸入檔案river.in的第一行有乙個正整數l(1 <= l <= 10^9),表示獨木橋的長度。第二行有三個正整數s,t,m,分別表示青蛙一次跳躍的最小距離,最大距離,及橋上石子的個數,其中1 <= s <= t <= 10,1 <= m <= 100。第三行有m個不同的正整數分別表示這m個石子在數軸上的位置(資料保證橋的起點和終點處沒有石子)。所有相鄰的整數之間用乙個空格隔開。

輸出

輸出檔案river.out只包括乙個整數,表示青蛙過河最少需要踩到的石子數。

如果本題資料範圍沒有這麼大,那麼將是一道非常簡單的dp。狀態轉移方程非常簡單:

設f[i]表示到達i點時所能踩得最少石子。

如果i點有石子:f[i]=min(f[i],f[i-j]+1)

如果i點沒有石子:f[i]=min(f[i],f[i-j])

但是看到這個題目的資料橋的長度<= 10^9,而石子的數量卻<= 100。所以這道題如果不加以離散化絕對會超時或者爆空間。那麼到底如何離散化呢?

我們其實可以將石子i與i-1之間的距離d[i]壓縮:

一。若距離在一跳之內就能跳完(或者一跳就會跳過),那麼距離無需壓縮:壓縮距離a[i]=a[i-1]+d[i]

二。若距離至少要兩跳及以上才能跳完,那麼距離就壓縮成兩跳。壓縮距離a[i]=a[i-1]+t+(d[i]%t);

壓縮完畢,接下來就是套用上面的狀態轉移方程,不過還有幾點要注意:

一。l也要壓縮,l=a[m]+((l-a[m])%t)+t。

二。青蛙最後一跳不一定剛剛好跳到橋尾,所以列舉的範圍應該是1到l+t-1

三。記得青蛙的跳躍範圍是s-t而不是1-t!

#include

using

namespace

std;

int len,s,t,m,a[101],f[10001],d[101],k[101],minn=10001;

bool b[1001];

int main()

for(int i=1;i<=m;i++)//離散化過程

len=a[m]+((len-a[m])%t)+t;

for(int i=1;i<=len+t-1;i++)//dp

for(int j=s;j<=t;j++)

if(i-j>=0 && i-jif(!b[i])f[i]=min(f[i],f[i-j]);

else f[i]=min(f[i],f[i-j]+1);

} for(int i=len;i<=len+t-1;i++)

minn=min(minn,f[i]);

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

}

謝謝觀賞~

NOIP2005 狀壓DP 過河

題目描述 題目背景 noip2005提高組試題2。在河上有一座獨木橋,乙隻青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點 0,1,l 其中l是橋的長度 座標為 0 的...

狀壓dp SCOI 2005 互不侵犯

題意 在n n n nn n的棋盤裡面放k kk個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8 88個格仔。考慮如何狀壓,對於每一行,我們用乙個長度為n nn的二進位制串表示每一行的狀態,比如1010 1010 1010 表示...

SCOI2005 互不侵犯(狀壓DP)

題意 給定乙個n n的棋盤,放置k個國王,使他們互相攻擊不到對方,共有多少種方案。國王可以攻擊上下左右,左上左下,右上右下附近的一格,共8格。資料範圍 1 n 9,0 k n n.因為n的範圍很小,而且每一行對應的乙個方案可以用乙個二進位制數表示,所以容易想到用狀壓dp。又因題目有限制要用多少個國王...