三个水杯问题

本文介绍了一个使用C语言实现的水量分配问题解决方案。通过深度优先搜索算法,找到从80L水杯向50L和30L水杯分配水,最终使80L水杯和50L水杯各含40L水的过程。

昨天在CSDN社区的C语言版看到了这样一个问题

有3个水杯A、B、C,容量分别为80L,50L,30L。现在有80L水装入A(B和C杯为空),A可以向B或C倒水。倒水要求:要么把别的杯子倒满,要么就自己倒空,倒水方向任意。最后要达到的目的是A杯有40L水,B杯有40L水,C杯无水。

看完以后很有兴趣,就写了自己的算法。虽然代码行数很多,但思路其实很简单:

  1. 找出当前状态下所有可能的路径。
  2. 按深度优先依次遍历路径,直到成功。
  3. 如果产生回路,则放弃这条路径。

#include <stdio.h>

#define MAXSTEP 100  /* the maximum number of steps allowed */
#define MAXPATH 6    /* the maximum number of path choices */

/* Choices when pouring water from one cup to another */
enum Path
{
    AToB,
    AToC,
    BToC,
    BToA,
    CToA,
    CToB
};

/* State of the 3 cups */
struct state
{
    int A;
    int B;
    int C;
};

struct state steps[MAXSTEP];  /* stores the steps of the process */
int sindex = 0;               /* indicates the next step position */

int paths[MAXPATH];           /* stores the choices in a specified state */
int pindex = 0;               /* indicates the next choice position */

/* function declaration */
int Run(struct state s);
void FindPaths(struct state s);
void Move(int index, struct state *s);
int BackToStart(struct state s);

main()
{
    struct state s = {80, 0, 0};  /* initial state */
    int i;

    steps[sindex++] = s;  /* store the first step */

    if (Run(s))  /* print the steps if succeed */
    {
        for (i = 0; i < sindex; i++)
            printf("(%d, %d, %d)/n", steps[i].A, steps[i].B, steps[i].C);
    }
}

/* Starts the process of pouring water */
int Run(struct state s)
{
    int i, index;
    struct state s1;

    FindPaths(s);  /* find all the choices in a specified state */

    /* back up the variables */
    index = sindex;
    s1 = s;

    /* go through all the choice */
    for (i = 0; i < pindex; i++)
    {
        /* set back to the state when starting the loop */
        sindex = index;
        s = s1;

        Move(i, &s);  /* move water according to the choice */
        if (BackToStart(s))  /* drop the path if it goes to the start point */
            continue;
        else
            steps[sindex++] = s;  /* store it if it's a new step */

        /* succeed or keep running */
        if ((s.A == 40 && s.B == 40 && s.C == 0) || Run(s))
            return 1;
    }

    return 0;  /* should not come here */
}

/* Finds all the choices in a specified state */
void FindPaths(struct state s)
{
    pindex = 0;  /* reset the indicator */

    if (s.A != 0 && s.B != 50)
        paths[pindex++] = AToB;
    if (s.A != 0 && s.C != 30)
        paths[pindex++] = AToC;
    if (s.B != 0 && s.C != 30)
        paths[pindex++] = BToC;
    if (s.B != 0 && s.A != 80)
        paths[pindex++] = BToA;
    if (s.C != 0 && s.A != 80)
        paths[pindex++] = CToA;
    if (s.C != 0 && s.B != 50)
        paths[pindex++] = CToB;
}

/* Moves water from one cup to another */
void Move(int index, struct state *s)
{
    /* only two possibilites: 1. empty the source cup;
       2. fill the destination cup. */
    switch (paths[index])
    {
    case AToB:
        if (s->A + s->B <= 50)  /* empty the source cup */
        {
            s->B += s->A;
            s->A = 0;
        }
        else                    /* fill the destination cup */
        {
            s->A -= 50 - s->B;
            s->B = 50;
        }
        break;
    case AToC:
        if (s->A + s->C <= 30)
        {
            s->C += s->A;
            s->A = 0;
        }
        else
        {
            s->A -= 30 - s->C;
            s->C = 30;
        }
        break;
    case BToC:
        if (s->B + s->C <= 30)
        {
            s->C += s->B;
            s->B = 0;
        }
        else
        {
            s->B -= 30 - s->C;
            s->C = 30;
        }
        break;
    case BToA:
        if (s->B + s->A <= 80)
        {
            s->A += s->B;
            s->B = 0;
        }
        else
        {
            s->B -= 80 - s->A;
            s->A = 80;
        }
        break;
    case CToA:
        if (s->C + s->A <= 80)
        {
            s->A += s->C;
            s->C = 0;
        }
        else
        {
            s->C -= 80 - s->A;
            s->A = 80;
        }
        break;
    case CToB:
        if (s->C + s->B <= 50)
        {
            s->B += s->C;
            s->C = 0;
        }
        else
        {
            s->C -= 50 - s->B;
            s->B = 50;
        }
        break;
    }
}

/* Checks if the state is same as a state before */
int BackToStart(struct state s)
{
    int i;

    for (i = 0; i < sindex; i++)
    {
        if (steps[i].A == s.A && steps[i].B == s.B && steps[i].C == s.C)
            return 1;
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值