CODE[VS] 1105 过河 状态压缩DP

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36404449/article/details/78251681

题目链接

题目描述 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;
}

猜你喜欢

转载自blog.csdn.net/qq_36404449/article/details/78251681