穿越河流的最短时间

时间:2016-03-13 20:24:19

标签: algorithm

一只青蛙正试图到达河的另一边。最初位于银行的一侧(位置-1)并且想要到达银行的另一侧(位置N)。

青蛙可以跳到1到D之间的任何距离。如果D小于N,青蛙不能直接跳跃。有一些石头可以帮助青蛙跳跃,但是只有在一定时间后水会不断减少,它们才会离开水面。只有当石头没有水时,青蛙才能跳进石头。 河流中的石头在阵列A中描述,由N个整数组成。 A [K]表示位置K处的石头将离开水的时间。 A [K] = - 1表示该位置没有石头。目标是找到青蛙可以到达另一家银行的最早时间。

  

示例D = 3,N = 6   A [0] = 1

     

A [1] = - 1

     

A [2] = 0

     

A [3] = 2

     

A [4] = 3

     

A [5] = 5

     

在第2时间,3颗石头将会缺水,青蛙可以跳3次跳到另一岸。

有人可以帮我解决这个问题吗?我想不出一个有效的方法来解决这个问题。

2 个答案:

答案 0 :(得分:5)

这是一个可能的解决方案:

通过将索引(i)推进到A[i]范围内最低时间的石头(A[i+1..i+D])来迭代数组。在每个步骤中,保持到目前为止找到的最长时间(maxTime = max(maxTime, A[i])。只要i < N-D重复此过程。完成此过程后,最长时间可在maxTime中找到。

复杂性为 O((N-D)D)

答案 1 :(得分:0)

这是一个非常简单的实现。

使用一个数组,即石头数加2:-1 =青蛙的银行,N =其他银行。

请注意使用访问宏AJ来允许否定索引:

// frogjmp/frogjmp -- jump frog across river

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define sysfault(_fmt...) \
    do { \
        printf(_fmt); \
        exit(1); \
    } while (0)

FILE *xfin;

int Dmax;                               // maximum allowable jump distance
int Nmax;                               // number of stones

// list of positions in river:
//   value is number of rounds needed to uncover a stone as valid jump-to place
//   -1 -- no stone at position
//   position is usable as jump-to point iff value is zero
//
//   special index values:
//     A(-1) is initial frog position (starting river bank)
//     A(Nmax) is the destination river bank
//
// the layout of this [and J] are:
//   frog's bank position | stones[Nmax] | other bank position
int *Aptr;                              // river state
#define A(_idx)     Aptr[(_idx) + 1]

int jmpcnt;                             // number of jumps used
int *Jptr;                              // jump history
#define J(_idx)     Jptr[(_idx) + 1]

int Tcur;                               // current time period / round
int Tmax;                               // maximum time for all stones uncovered

// getval -- read in numeric value
int
getval(const char *sym,int idx)
{
    char prompt[100];
    char *bp;
    char linebuf[1000];
    int val;

    bp = prompt;
    bp += sprintf(bp,"%s",sym);
    if (idx >= 0)
        bp += sprintf(bp,"[%d]",idx);
    bp += sprintf(bp,": ");

    // interactive -- show prompt
    if (xfin == stdin) {
        fputs(prompt,stdout);
        fflush(stdout);
    }

    // get line
    bp = fgets(linebuf,sizeof(linebuf),xfin);
    if (bp == NULL)
        sysfault("getval: premature EOF\n");

    // isolate the number
    bp = strtok(linebuf," \t\n");
    if (bp == NULL)
        sysfault("getval: empty line\n");

    // get the number value
    val = atoi(bp);

    // file input -- show prompt and value read
    if (xfin != stdin) {
        fputs(prompt,stdout);
        printf("%d\n",val);
    }

    return val;
}

// chkbad -- check for impossible (too many -1 values in a row)
void
chkbad(int lo)
{
    int hi;
    int idx;
    int badflg;

    badflg = 1;
    hi = lo + Dmax;

    if (hi > Nmax) {
        hi = Nmax;
        badflg = 0;
    }

    for (idx = lo;  idx < hi;  ++idx) {
        if (A(idx) >= 0) {
            badflg = 0;
            break;
        }
    }

    if (badflg)
        sysfault("chkbad: impossible\n");
}

// jmpshow -- show river state with jumps
void
jmpshow(void)
{
    int idx;
    int val;

    printf("A:");

    for (idx = 0;  idx <= Nmax;  ++idx) {
        val = A(idx);
        printf(" %d=%d%s",idx,val,J(idx) ? "<" : " ");
    }

    printf("\n");
}

// frogjmp -- jump the frog to the farthest reachable position from current one
// RETURNS: new frog position (-1=nothing valid)
int
frogjmp(int frogcur)
// frogcur -- current frog position
{
    int idx;
    int lo;
    int hi;
    int val;
    int best;

    // get range of possible jump-to positions from the current frog position
    lo = frogcur + 1;
    hi = frogcur + Dmax;
    if (hi > Nmax)
        hi = Nmax;

    // find the farthest/best jump (i.e. the _last_ valid jump we find here)
    // A values:
    //   <0 -- no stone in position
    //    0 -- stone/position can be jumped to now
    //   >0 -- stone can't be jumped to now -- will be uncovered in future round
    best = -1;
    for (idx = lo;  idx <= hi;  ++idx) {
        val = A(idx);
        if (val == 0)
            best = idx;
    }

    // found a landing point -- advance jump count and mark it as being jumped
    // to
    if (best >= 0) {
        jmpcnt += 1;
        J(best) = 1;
    }

    return best;
}

// dotime -- process current time period
// RETURNS: 1=frog on other side
int
dotime(void)
{
    int frogcur;
    int idx;
    int doneflg;

    printf("dotime: time %d\n",Tcur);

    // reset the jump history
    jmpcnt = 0;
    for (idx = -1;  idx <= Nmax;  ++idx)
        J(idx) = 0;
    J(-1) = 1;

    // show state at start of time period
    jmpshow();

    // frog always starts here
    frogcur = -1;

    doneflg = 0;
    while (1) {
        // find the best position (farthest) to jump to from the current
        // position
        // bug out if no place to jump to found within this round (i.e. we
        // can't get to the other side without a new drain operation)
        frogcur = frogjmp(frogcur);
        if (frogcur < 0)
            break;

        // stop when frog gets to the other side -- we're done
        if (frogcur >= Nmax) {
            doneflg = 1;

            printf("dotime: frog landed at time %d after %d jumps\n",
                Tcur,jmpcnt);
            jmpshow();

            break;
        }

        // show state after current jump
        jmpshow();
    }

    return doneflg;
}

// dodrain -- drain river by one level
void
dodrain(void)
{
    int idx;
    int val;

    // bump down the level for each stone: the time remaining before it becomes
    // accessible/usable
    // we only do this for "covered" stones, never for non-existent ones or
    // ones that are already "uncovered"
    for (idx = 0;  idx < Nmax;  ++idx) {
        val = A(idx);
        if (val > 0)
            A(idx) = val - 1;
    }
}

// dofile -- process test
void
dofile(void)
{
    int idx;

    // get the maximum jump the frog can do
    Dmax = getval("D",-1);

    // get the number of stones/positions in the river
    Nmax = getval("N",-1);

    // get enough space for the [in river] stone positions + the bank positions
    Aptr = malloc(sizeof(int) * (Nmax + 2));
    Jptr = malloc(sizeof(int) * (Nmax + 2));

    // get values for all the stones in the river
    Tmax = -1;
    for (idx = 0;  idx < Nmax;  ++idx) {
        Tcur = getval("A",idx);
        A(idx) = Tcur;
        if (Tcur > Tmax)
            Tmax = Tcur;
    }

    // the river banks are always accessible jump points (i.e. they're _not_
    // "covered")
    A(-1) = 0;
    A(Nmax) = 0;

    // show the initial state after reading inpu
    jmpshow();

    // check for impossible river
    for (idx = 0;  idx < Nmax;  ++idx)
        chkbad(idx);

    // do all possible time periods
    for (Tcur = 0;  Tcur <= Tmax;  ++Tcur) {
        // test the current river state to see if frog can make it across now
        // stop when we're done
        if (dotime())
            break;

        // we were blocked by some inaccessible jump
        // drain the river by a level in prep for next time period
        // this makes _some_ stones [based on their updated values] as valid
        // jump-to points for the next round that may not have been accessible
        // during the current round
        dodrain();
    }

    free(Aptr);
    free(Jptr);
}

// main -- main program
int
main(int argc,char **argv)
{
    char *cp;

    --argc;
    ++argv;

    if (argc <= 0) {
        xfin = stdin;
        dofile();
    }

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        xfin = fopen(cp,"r");
        if (xfin == NULL)
            sysfault("main: unable to open '%s' -- %s\n",cp,strerror(errno));
        dofile();
        fclose(xfin);
    }
}

以下是示例输入的程序输出:

D: 3
N: 6
A[0]: 1
A[1]: -1
A[2]: 0
A[3]: 2
A[4]: 3
A[5]: 5
A: 0=1  1=-1  2=0  3=2  4=3  5=5  6=0
dotime: time 0
A: 0=1  1=-1  2=0  3=2  4=3  5=5  6=0
A: 0=1  1=-1  2=0< 3=2  4=3  5=5  6=0
dotime: time 1
A: 0=0  1=-1  2=0  3=1  4=2  5=4  6=0
A: 0=0  1=-1  2=0< 3=1  4=2  5=4  6=0
dotime: time 2
A: 0=0  1=-1  2=0  3=0  4=1  5=3  6=0
A: 0=0  1=-1  2=0< 3=0  4=1  5=3  6=0
A: 0=0  1=-1  2=0< 3=0< 4=1  5=3  6=0
dotime: frog landed at time 2 after 3 jumps
A: 0=0  1=-1  2=0< 3=0< 4=1  5=3  6=0<

<强>更新

程序在从初始状态到最后一轮的时间段内迭代(即最高的“石头”值):T0,T1,......

在每一轮中,青蛙从最初的河岸开始。对于给定的青蛙位置,根据青蛙的最大可能跳跃范围和该范围内的宝石的当前状态计算最远的“跳跃”位置。如果找到这样一个有效的跳转位置(即跳转位置的值为零),则重复该过程,直到青蛙在另一个岸上。

如果没有找到跳转位置(即进度被不存在和/或覆盖的石头阻挡),则石头“覆盖”级别减1。然后,开始新一轮。