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;
}

 

posted @ 2018-02-10 10:07  planche  阅读(159)  评论(0编辑  收藏  举报