zoukankan      html  css  js  c++  java
  • P1052 过河

    题目描述 
    在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点: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只包括一个整数,表示青蛙过河最少需要踩到的石子数。

    输入输出样例 
    输入样例#1: 复制 
    10 
    2 3 5 
    2 3 5 6 7 
    输出样例#1: 复制 
    2

    解析:

    语文理解好一点,不是必须踩着石头过河,是尽量少的踩石头!!! 
    dp[i]代表距离起点为i走的最少石头数

    状态转移方程: 
    dp[i]=min(dp[i],dp[j]+stone[i]);

    但是这里距离太大,而且十分离散 
    所以这里需要路径压缩 
    选取lcd(9,10)=90这个数,为什么? 
    需要用到扩展欧几里得: 
    把题目转化为:

    二元一次不定方程:ax+by=c, 且gcd(a,b)=1 (a,b为两种步数走法,c为达到距离)(x,y为用a,b这两种步数的次数) 
    证明存在(x,y)的非负整数解的c的最小值为lcm(a,b)=ab

    证明: 
    x的通解 x=x0+bt(t>=0且为整数) 
    这里我们不妨设x0=0(取最小的那个特解)

    1.当x!=0时: 
    x=bt(t>=1且t为整数) 
    所以 x>=b 
    所以 c>=ax>=ab

    2.当x==0时 
    则by=c 
    则存在当y>=a时,可以满足c>=ab成立

    综上:当c=ab时,方程总是存在非负整数解

    所以对于这题来说,只要取两个不同最大步数9,10处理,可得90为最小值

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 40000
    typedef long long ll;
    #define inf 9999999999
    #define ri register int
    #define getchar() (Ss==Tt&&(Tt=(Ss=BB)+fread(BB,1,1<<15,stdin),Ss==Tt)?EOF:*Ss++)
    char BB[1 << 18], *Ss = BB, *Tt = BB;
    inline int read()
    {
        int x=0;
        int ch=getchar(),f=1;
        while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
        if (ch=='-')
        {
            f=-1;
            ch=getchar();
        }
        while (isdigit(ch))
        {
            x=(x<<1)+(x<<3)+ch-'0';
            ch=getchar();
        }
        return x*f;
    }

    int n;
    int s,t;
    int L,m;
    int a[maxn];
    int b[maxn];
    int ans=0;
    int dp[maxn];

    int main()
    {
    //    freopen("test.txt","r",stdin);
        memset(dp,0x3f,sizeof(dp));
        L=read();
        L=0;
        s=read(),t=read(),m=read();
        if(s==t)
        {
            int x;
            for(int i=1; i<=m; i++)
            {
                x=read();
                if(x%s==0)ans++;
            }
            cout<<ans;
            return 0;
        }
        for(int i=1; i<=m; i++)
            b[i]=read();

        sort(b+1,b+m+1);

        for(int i=1; i<=m; i++)
        {
            int x=b[i]-b[i-1];
            if(x>90)L+=90;
            else L+=x;
            a[L]=1;
        }


        for(int i=s; i<=t; i++)
            dp[i]=a[i]?1:0;

        for(int i=t+1; i<=L+t; i++)
            for(int j=i-t; j<=i-s; j++)
            {
                if(j<0)continue;
                dp[i]=min(dp[i],dp[j]+(a[i]?1:0));
            }

        ans=inf;
        for(int i=L; i<=L+t; i++)
            ans=min(ans,dp[i]);
        cout<<ans;

        return 0;
    }

  • 相关阅读:
    网络基础 03 交换机基本原理与配置
    网络基础 02 网络布线与数制转换
    C#操作excel(读取excel里的图片并show在页面上)
    让IIS支持中文文件名和目录
    Asp.net中防止用户多次登录的方法
    【转摘】一道关于实例化顺序的C#面试题
    选项卡调其他窗体方法
    同一个工作组的计算机能ping通不能访问对方共享资源
    Combobox出现System.Data.DataRowView的原因,以及指定ValueMember的时机问题
    无法嵌入互操作类型“Microsoft.Office.Interop.Excel.ApplicationClass”。请改用适用的接口。
  • 原文地址:https://www.cnblogs.com/planche/p/8438166.html
Copyright © 2011-2022 走看看