CODE[VS] 1105 過河 狀態壓縮DP

題目鏈接

題目描述 Description
在河上有一座獨木橋,一隻青蛙想沿着獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點:0,1,……,L(其中L是橋的長度)。座標爲0的點表示橋的起點,座標爲L的點表示橋的終點。青蛙從橋的起點開始,不停的向終點方向跳躍。一次跳躍的距離是S到T之間的任意正整數(包括S,T)。當青蛙跳到或跳過座標爲L的點時,就算青蛙已經跳出了獨木橋。題目給出獨木橋的長度L,青蛙跳躍的距離範圍S,T,橋上石子的位置。你的任務是確定青蛙要想過河,最少需要踩到的石子數。
輸入描述 Input Description
輸入第一行有一個正整數L(1<=L<=10e9),表示獨木橋的長度。第二行有三個正整數S,T,M,分別表示青蛙一次跳躍的最小距離,最大距離,及橋上石子的個數,其中1<=S<=T<=10,1<=M<=100。第三行有M個不同的正整數分別表示這M個石子在數軸上的位置(數據保證橋的起點和終點處沒有石子)。所有相鄰的整數之間用一個空格隔開。
輸出描述 Output Description
輸出只包括一個整數,表示青蛙過河最少需要踩到的石子數。
水題分析 Waterproblem Analysis
本來想在考試之前,苦練一發DP,在歷年原題裏面找了找,沒想到這麼不幸運發現這麼一個題。一開始只想着思考思考狀態轉移方程,但是題目100%的數據L<=10e9,按NOIp的尿性後面這七十個點L==10e9沒跑了,一開始想到只用每一個石子的位置代表每一個狀態,但是發現自己太弱了不會轉移方程,思索了半天以後就棄了。想了想只做30%的就可以了。那這個題就非常簡單了。以每一個橫座標爲一個狀態,那麼着個狀態就可以由走j步轉移過來即:f[i]=min(f[i],f[i-j]+stone[i]);(i>=j)
在注意一下邊界即可,因爲題目中說明跳過L也可。
而對於100%的數據,觀察可知L這麼範圍很大,而石頭數量只有<=100個,那麼對於中間很大一部分的區域都是可以跳到的而對於後面的結果沒有任何影響,那麼我們就可以將兩石頭之間的距離縮短,現在問題就變爲,求青蛙最小可以連續都能跳到的距離。考慮最壞的情況S=9,T=10。xT+y(T-1)=Q
x,y是正整數,T,T-1是一步跳躍的距離,對於Q>=T*(T-1),一定有x,y正整數解。那麼對於大於T^2的距離對答案就是沒有影響的了,那麼我們考慮最差情況,對每兩個石頭之間的距離%100,那L=10e7,對於每一個狀態都可以開一維數組存儲了。
另外:題目描述可知S是可以與T相等的,那麼我們特判一下可以節省不少的時間。

附上代碼

#include<iostream>//30分
#include<cstring>
using namespace std;
int L,S,T,m; 
int f[10010];
bool w[10010];
int main()
{
    cin>>L>>S>>T>>m;
    for(int i=1;i<=m;i++)
    {
        int stone;
        cin>>stone;
        w[stone]=1;
    }
    memset(f,127,sizeof(f));
    f[0]=0;
    for(int i=S;i<=L+T;i++)
    {
        for(int j=S;j<=T;j++)
        {
            f[i]=min(f[i],f[i-j]+w[i]);             
        }
    }
    int ans=1000000000; 
    for(int i=L;i<=L+T;i++)ans=min(ans,f[i]);
    cout<<ans;
}
#include<iostream>//100分
#include<algorithm>
#include<cstring>
using namespace std;
int L,s,t,m;
int w[201],d[201],f[1000010];
bool stone[1000010];
int solve()
{
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        if(w[i]%s==0)
        ans++;
    }
    cout<<ans;
    return 0;
}
int main()
{
    cin>>L>>s>>t>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>w[i];
    }
    if(s==t)
    {
        solve();
        return 0;
    }
    sort(w+1,w+m+1);
    for(int i=1;i<=m;i++)
    {
        d[i]=w[i]-w[i-1];
    }
    int start=0;
    for(int i=1;i<=m;i++)
    {
        start=start+(d[i]%100);
        stone[start]=1;
    }
    L=start+(L-w[m])%100;
    memset(f,127,sizeof(f));
    f[0]=0;
    for(int i=s;i<=L+t;i++)
    {
        for(int j=s;j<=t;j++)
        {
            f[i]=min(f[i],f[i-j]+stone[i]);
        }
    }
    int ans=1000000000;
    for(int i=L;i<=L+t;i++)ans=min(ans,f[i]);
    cout<<ans;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章