2个空水壶,容积分别为3升和7升,如何只用这2个水壶从池塘里取得5升的水 -- 之程序实现

来源:互联网 发布:ios windows 编辑:程序博客网 时间:2024/04/28 23:58

又一次切换工作,在工作交接期间,有些时间来访问CSDN了


当时闲的无事,把下面的一个高校俱乐部的问题用程序来实现了下,暂时发现有3种方案:

1.  穷举法,不断的尝试,找到符合要求的方案

2. 使用迪斯特拉算法,找到最优的算法及操作方案

3. 类似能量守恒定理,可以解释得到如下不定方程:3x+7y=5;     #如果此方程通过数学定理可以解释,那么一切的类似问题都非常简单了...


有两年没有写代码了,还有很多可以优化的地方

马上要忙起来了,我这边先这样, 如果有时间,再来处理吧...


假设有一个池塘,里面有无穷多的水。现有2个空水壶,容积分别为3升和7升。问题是如何只用这2个水壶从池塘里取得5升的水。


/****************************************************************************************
Function: Two bottles, one bottle container is 3L, another one is 7L;
        There is enough water in the bucket, we should use that two bottles to get 5L water.

Comments:    
        1. Use status machine to get every valid operations
        2. Use stack to save current water status and next operations.
        3. We assume the operation steps less than MAX_OPERATION_STEPS
        4. We assume that get the water from bucket should be less than MAX_IN_WATER

Ver0.11:    
        1. Try to search all of the ways to get the operation steps   

Ver0.12:    
        1. How to get the min value? Dijekstr's Algorithm?   
        2. Dojkestra Algorithm passed.   
        3. Save the shortest path       

Ver0.13:    
        1. We can use below expresion to get the operation steps:
            CONTAINER_3L * x + CONTAINER_7L * y == CONTAINER_TARGET        
        2. Because we can think it like this:
            a. There are two bottles, if we arrived the target, that's mean "CONTAINER_7L" bottle has CONTAINER_TARGET water
                and we can OUTPUT all of the water in "CONTAINER_3L" bottle after we arrived the target.
                 INPUT - OUTPUT == CONTAINER_TARGET; SHIFT operation can't add/dicrease any water.
            b. It can't be INPUT/OUT water not "mod" CONTAINER_3L or CONTAINER_7L;
                We haven't other container, so every INPUT/OUTPUT should be used by CONTAINER_3L/7L;
                If it input/out value is not mod "CONTAINER_3L/7L", it will be occurs from previous operation which from 3L/7L.
                so INPUT-OUTPUT == CONTAINER_3L * x + CONTAINER_7L * y
                
Creater: work2free

*****************************************************************************************/

#include "iostream.h"    //just used VC compiler.

//#define DIJKESTRA

#define INPUT_OUTPUT_MODE

#define CONTAINER_3L 3
#define CONTAINER_7L 7
#define MAX_STATUS (CONTAINER_3L + 1) * (CONTAINER_7L + 1)
#define CONTAINER_TARGET 5
#define MAX_OPERATION_STEPS ((MAX_STATUS) * (MAX_STATUS) + 1)
#define MAX_IN_WATER 200

//The operations should be only in these enum type.
typedef enum {
    IN_3L,
    OUT_3L,
    SHIFT_3L_7L,
    IN_7L,
    OUT_7L,
    SHIFT_7L_3L,
    E_OPERATION_ERROR,
}E_Operation;

//current bottles contain how much water
typedef struct Node_Tag {
    int value_3L;
    int value_7L;
    E_Operation operation;
    int min_value;    //
}Node_T;


static int s_status_operation_map [CONTAINER_3L + 1][CONTAINER_7L + 1][E_OPERATION_ERROR];        //(CONTAINER_3L + 1)*(CONTAINER_7L + 1) * E_OPERATION_ERROR
static Node_T s_statck_array[MAX_OPERATION_STEPS];
static unsigned int s_statck_index;    //The value means there is how many node in the stack

static Node_T s_save_min_array[MAX_OPERATION_STEPS];
static unsigned int s_min_index;    //The value means there is how many node in the stack

static int s_total_min = MAX_IN_WATER;

//  return 1 means valid
int JudgeValidOperation (int value_3L, int value_7L, E_Operation operation)
{
    if (value_3L > CONTAINER_3L || value_7L > CONTAINER_7L)
    {
        return -1;
    }
    
    switch (operation)
    {
        case IN_3L:
        {
            if (value_3L < CONTAINER_3L)
            {
                return 1;
            }
            
            return 0;
        }
            
        case OUT_3L:
        {
            if (value_3L != 0)
            {
                return 1;
            }
            
            return 0;
        }
                    
        case SHIFT_3L_7L:
        {
            if (value_3L != 0 && value_7L < CONTAINER_7L)
            {
                return 1;
            }
            
            return 0;
        }
        
        case IN_7L:
        {
            if (value_7L < CONTAINER_7L)
            {
                return 1;
            }
            
            return 0;
        }
                
        case OUT_7L:
        {
            if (value_7L != 0)
            {
                return 1;
            }
            
            return 0;
        }
        
        case SHIFT_7L_3L:
        {
            if (value_7L != 0 && value_3L < CONTAINER_3L)
            {
                return 1;
            }
            
            return 0;
        }
            
        default:
            return 0;
    }

    return 0;
}

int InitStatusOperationMap ()
{
    int iloop_value_3L;
    int iloop_value_7L;
    E_Operation iloop_operation;
    
    for (iloop_value_3L = 0; iloop_value_3L <= CONTAINER_3L; iloop_value_3L ++)
    {
        for (iloop_value_7L = 0; iloop_value_7L <= CONTAINER_7L; iloop_value_7L ++)
        {
            for (iloop_operation = 0; iloop_operation <= SHIFT_7L_3L; iloop_operation ++)
            {
                s_status_operation_map[iloop_value_3L][iloop_value_7L][iloop_operation] =
                    JudgeValidOperation (iloop_value_3L, iloop_value_7L, iloop_operation);
                if (s_status_operation_map[iloop_value_3L][iloop_value_7L][iloop_operation] == -1)
                {
                    printf ("InitStatusOperationMap ERROR: iloop_value_3L = %d, iloop_value_7L = %d, iloop_operation = %d\n", iloop_value_3L, iloop_value_7L, iloop_operation);
                    return -1;
                }
            }
        }
    }
}

int GetStackTotalWater ()
{
    int iloop = 0;
    int total_water = 0;

    if (s_statck_index == 1)    //only one
        return (s_statck_array[iloop].value_3L + s_statck_array[iloop].value_7L);
    
    //Check whether total IN water more than 15
    for (iloop = 0; iloop < s_statck_index - 1; iloop ++)
    {
        //Water total value is large than min
        if (s_statck_array[iloop].operation == IN_3L)
        {
            if (iloop == 0)
            {
                total_water += CONTAINER_3L;
            }
            else
            {
                total_water += (CONTAINER_3L - s_statck_array[iloop].value_3L);
            }
        }
        else if  (s_statck_array[iloop].operation == IN_7L)
        {
            if (iloop == 0)
            {
                total_water += CONTAINER_7L;
            }
            else
            {
                total_water += (CONTAINER_7L - s_statck_array[iloop].value_7L);
            }        
        }
    }

    return total_water;
}

int OperateResult (Node_T current_node, Node_T *result_node_p)
{
    if (result_node_p == 0)
    {
        return -1;
    }
    result_node_p->value_3L = current_node.value_3L;
    result_node_p->value_7L = current_node.value_7L;
    
    if (JudgeValidOperation (current_node.value_3L, current_node.value_7L, current_node.operation) == 1)
    {
        switch (current_node.operation)
        {
            case IN_3L:
            {
                if (result_node_p->value_3L != CONTAINER_3L)
                {
                    result_node_p->value_3L = CONTAINER_3L;
                    return 1;
                }

                return 0;
            }
                
            case OUT_3L:
            {
                result_node_p->value_3L = 0;
                return 1;
            }
                        
            case SHIFT_3L_7L:
            {
                if (current_node.value_7L == CONTAINER_7L || result_node_p->value_3L == 0)
                    return 0;

                if (current_node.value_3L + current_node.value_7L > CONTAINER_7L)
                {
                    result_node_p->value_3L = current_node.value_3L + current_node.value_7L - CONTAINER_7L;
                    result_node_p->value_7L = CONTAINER_7L;
                    
                    return 1;
                }
                else
                {
                    result_node_p->value_7L = current_node.value_3L + current_node.value_7L;
                    result_node_p->value_3L = 0;

                    return 1;
                }
            }
            
            case IN_7L:
            {
                if (result_node_p->value_7L != CONTAINER_7L)
                {
                    result_node_p->value_7L = CONTAINER_7L;
                    return 1;
                }

                return 0;
            }
                    
            case OUT_7L:
            {
                result_node_p->value_7L = 0;
                return 1;
            }
            
            case SHIFT_7L_3L:
            {
                if (current_node.value_7L == 0 || result_node_p->value_3L == CONTAINER_3L)
                    return 0;

                if (current_node.value_3L + current_node.value_7L > CONTAINER_3L)
                {
                    result_node_p->value_7L = current_node.value_3L + current_node.value_7L - CONTAINER_3L;
                    result_node_p->value_3L = CONTAINER_3L;
                    return 1;
                }
                else
                {
                    result_node_p->value_3L = current_node.value_3L + current_node.value_7L;
                    result_node_p->value_7L = 0;

                    return 1;
                }

                return 0;
            }
                
            default:
                return 0;
        }
    }
    else
    {
        return -1;
    }
}

int JudgeTopNodeValid ()
{
    int total_water = GetStackTotalWater ();
    int iloop = 0;
    Node_T result_node = {0, 0, IN_3L};

    if (s_statck_index == 0)
        return 0;

    if (JudgeValidOperation (s_statck_array[s_statck_index - 1].value_3L,
                        s_statck_array[s_statck_index - 1].value_7L,
                        s_statck_array[s_statck_index - 1].operation) != 1)
        return 0;
        
    //Check whether the operation result is the same as previous node
    if (!OperateResult (s_statck_array[s_statck_index - 1], &result_node))    //The operation is the same as previous one
        return 0;
        
    for (iloop = 0; iloop < s_statck_index - 1; iloop ++)
    {
        if (s_statck_array[iloop].value_3L == result_node.value_3L
            && s_statck_array[iloop].value_7L == result_node.value_7L)
        return 0;
    }

    //We should find a way to get the latest water
    //if (s_total_min < GetStackTotalWater ())
    {
        //return 0;
    }

    return 1;
}

#ifdef DIJKESTRA

#define MAX_VERTEX_NUM (MAX_STATUS)
#define ERROR_VERTEX (MAX_VERTEX_NUM + 2)
#define MAX_DISTANCE 1000000
//using namespace std;
//int s_num_vertex = MAX_STATUS;        //vertex number
int s_arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    
int s_shortest_distance[MAX_VERTEX_NUM];    //Save shortest length
int s_exist_path[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//path
int s_shortest_vertex_gather[MAX_VERTEX_NUM];//if s_shortest_vertex_gather[i] == 1, that's mean the vertex already in gather V.

int s_start_vertex = 0;    //start vertex (0, 0)
int s_end_vertex = CONTAINER_TARGET;    //end vertex  (0, 5)

int s_path[ERROR_VERTEX][ERROR_VERTEX];        //from s_start_vertex to s_end_vertex, if there is path, save all of the passed vertex

//Only compute in water value
int GetOperationDistance (int value_3L, int value_7L, E_Operation operation)
{
    int distance = 0;
    
    if (value_3L > CONTAINER_3L || value_7L > CONTAINER_7L)
    {
        return -1;
    }
    
    switch (operation)
    {
        case IN_3L:
        {
            if (value_3L < CONTAINER_3L)
            {
                distance = CONTAINER_3L - value_3L;
            }
            
            return distance;
        }
            
        case IN_7L:
        {
            if (value_7L < CONTAINER_7L)
            {
                distance = CONTAINER_7L - value_7L;
            }
            
            return distance;
        }

        case OUT_3L:
        case SHIFT_3L_7L:
        case OUT_7L:
        case SHIFT_7L_3L:
        {
            return 0;
        }
            
        default:
            return 0;
    }

    return 0;
}

int InitDijkstraArcs ()
{
    int iloop_from_index = 0;        //from vertex
    int iloop_to_index = 0;        //to vertex

    int from_value_3L = 0;
    int from_value_7L = 0;
    
    int to_index = 0;
    
    int iloop_operation = 0;
    
    for (iloop_from_index = 0; iloop_from_index <= MAX_STATUS; iloop_from_index ++)
    {
        //default: set the distance is max, self vertex exists path and distance is 0
        for (iloop_to_index = 0; iloop_to_index <= MAX_STATUS; iloop_to_index ++)
        {
            s_arcs[iloop_from_index][iloop_to_index] = MAX_DISTANCE;

            //self vertex: there is path and the distance is 0
            if (iloop_to_index == iloop_from_index)
            {
                s_arcs[iloop_from_index][iloop_to_index] = 0;
            }
        }

        //check:the operation has some path
        for (iloop_operation = 0; iloop_operation < E_OPERATION_ERROR; iloop_operation ++)
        {
            Node_T from_vertex;
            Node_T to_vertex;
            int operate_result = 0;

            from_value_3L = iloop_from_index/(CONTAINER_7L + 1);
            from_value_7L = iloop_from_index%(CONTAINER_7L + 1);

            from_vertex.value_3L = from_value_3L;
            from_vertex.value_7L = from_value_7L;
            from_vertex.operation = iloop_operation;
            
            operate_result = OperateResult (from_vertex, &to_vertex);
            if (operate_result == 1)        //there is path
            {
                to_index = to_vertex.value_3L * (CONTAINER_7L + 1) + to_vertex.value_7L;
                s_arcs[iloop_from_index][to_index] = GetOperationDistance (from_value_3L, from_value_7L, iloop_operation);
            }
        }
    }
}

void ShortestPath_DIJ ()
{     
    int iloop = 0;
    int iloop_tmp = 0;
    int iloop_v = 0;
    int current_v = 0;
    int iloop_w = 0;

    //Init the paths:
    for (iloop = 0; iloop < MAX_VERTEX_NUM; iloop ++)
    {
        for (iloop_tmp = 0; iloop_tmp < MAX_VERTEX_NUM; iloop_tmp ++)
        {
            s_path[iloop][iloop_tmp] = ERROR_VERTEX;
        }
    }
    
    //Init distances: From start vertex to other vertex which can directly reach to.
    for (iloop = 0; iloop < MAX_VERTEX_NUM; iloop ++)
    {
        s_shortest_distance[iloop] = s_arcs[s_start_vertex][iloop];    
        s_exist_path[s_start_vertex][MAX_VERTEX_NUM] = 1;

        s_shortest_vertex_gather[iloop] = 0;
    }
    
    //Search the shortest distance vertex "one by one"
    for (iloop = 1; iloop < MAX_VERTEX_NUM; iloop ++)        //start vertex can be removed, so iloop = 1, not 0;
    {
        int min = MAX_DISTANCE;

        //pick out shortest connected vertex to gather V
        for (iloop_v = 0; iloop_v < MAX_VERTEX_NUM; iloop_v ++)    
        {
            if (s_shortest_vertex_gather[iloop_v] == 0
                && s_shortest_distance[iloop_v] < min)
            {
                min = s_shortest_distance[iloop_v];    //from "s_start_vertex" to shortest vertex which index is "iloop_v"
                current_v = iloop_v;

                for (iloop_tmp = 0; iloop_tmp < MAX_VERTEX_NUM; iloop_tmp ++)
                {
                    if (s_path[current_v][iloop_tmp] == ERROR_VERTEX)
                    {
                        s_path[current_v][iloop_tmp] = current_v;
                        break;
                    }
                }
            }
        }
        s_shortest_vertex_gather[current_v] = 1;        //add the vertex to gather V;

        //set the distance which connected with "current_v" vertex
        for (iloop_w = 0; iloop_w < MAX_VERTEX_NUM; iloop_w ++)
        {
            if (s_shortest_vertex_gather[iloop_w] != 1        //Not in gather V
                && (min + s_arcs[current_v][iloop_w] < s_shortest_distance[iloop_w]))        //current_v vertex connected with iloop_w vertex
            {
                s_shortest_distance[iloop_w] = min + s_arcs[current_v][iloop_w];
                s_exist_path[current_v][iloop_w] = 1;

                memcpy (&s_path[iloop_w][0], &s_path[current_v][0], sizeof(int) * ERROR_VERTEX);
                for (iloop_tmp = 0; iloop_tmp < MAX_VERTEX_NUM; iloop_tmp ++)
                {
                    if (s_path[iloop_w][iloop_tmp] == ERROR_VERTEX)
                    {
                        s_path[iloop_w][iloop_tmp] = iloop_w;
                        break;
                    }
                }
            }
        }
    }
}     
                
int main ()
{     
    InitDijkstraArcs ();
    ShortestPath_DIJ ();
    
    return 0;
}

#elif defined INPUT_OUTPUT_MODE

int GetOperationStepsByInputOutCount (int count_3l, int count_7l)
{
    //We should ensure operation steps: total "input > output"
    
}

int CountOne (int value)
{
    int iloop = 0;
    int count = 0;
    for (iloop = 0; iloop < 32; iloop ++)
    {
        if ((value & (0x01 << iloop)))
        {
            count ++;
        }
    }

    return count;
}

void main ()
{
    int iloop_count_3l = 0;
    int iloop_count_7l = 0;
    int count_3l = 0;    //> 0 means INPUT,
    int count_7l = 0;
    int min = MAX_IN_WATER;

    int total_count = 0;    //include input/output
    int iloop_total_operation = 0;    //how many conbinations for INPUT/OUTPUT
    int operation_result = 0;    //how many conbinations for INPUT/OUTPUT
    int iloop_bit = 0;
    int current_contains = 0;
    
    //Get input/out count
    for (iloop_count_3l = -10; iloop_count_3l < 10; iloop_count_3l ++)
    {
        for (iloop_count_7l = -10; iloop_count_7l < 10; iloop_count_7l ++)
        {
            if (iloop_count_3l * CONTAINER_3L + iloop_count_7l * CONTAINER_7L == CONTAINER_TARGET)
            {
                int input = 0;
                
                if (iloop_count_3l > 0)
                    input += iloop_count_3l  * CONTAINER_3L;
                if (iloop_count_7l > 0)
                    input += iloop_count_7l  * CONTAINER_7L;

                if (min > input)
                {
                    min = input;
                    count_3l = iloop_count_3l;
                    count_7l = iloop_count_7l;
                }
                
                printf ("iloop_count_3l == %d, iloop_count_7l == %d \n", iloop_count_3l, iloop_count_7l);
            }
        }
    }

    //total_count
    if (count_3l < 0)
    {
        total_count = (-count_3l) + count_7l;
    }
    else if (count_7l < 0)
    {
        total_count = (-count_7l) + count_3l;
    }

    // use the binary bit: 1 means input, 0 means output
    for (iloop_total_operation = 0; iloop_total_operation < (0x01 << total_count); iloop_total_operation ++)
    {
        int one_num = CountOne (iloop_total_operation);

        if (count_3l > 0 && one_num == count_3l)    //input 3L
        {
            for (iloop_bit = 0; iloop_bit < total_count; iloop_bit ++)
            {
                if (iloop_total_operation & (0x01 << iloop_bit))        //IN
                {
                    current_contains += CONTAINER_3L;
                }
                else //OUT
                {
                    current_contains -= CONTAINER_7L;
                }

                //This operation is invalid
                if (current_contains < 0 || current_contains > 10)
                    break;

                if (current_contains == CONTAINER_TARGET)
                {
                    operation_result = iloop_total_operation;
                    break;
                }
            }
        }
        else if (count_7l > 0 && one_num == count_7l)    //input 7L
        {
            for (iloop_bit = 0; iloop_bit < total_count; iloop_bit ++)
            {
                if (iloop_total_operation & (0x01 << iloop_bit))        //IN
                {
                    current_contains += CONTAINER_7L;
                }
                else //OUT
                {
                    current_contains -= CONTAINER_3L;
                }

                //This operation is invalid
                if (current_contains < 0 || current_contains > 10)
                    break;

                if (current_contains == CONTAINER_TARGET)
                {
                    operation_result = iloop_total_operation;
                    break;
                }
            }

        }

        current_contains = 0;    //clear status.
        
        if (operation_result)
            return operation_result;
    }
}

#else
void main ()
{
    Node_T current_node = {0, 0, IN_3L};    //
    int total = 0;
    
    InitStatusOperationMap ();

    //Create first node
    current_node.value_3L = 0;
    current_node.value_7L = 0;
    current_node.operation = IN_3L;

    //Push stack
    memcpy(&s_statck_array[s_statck_index], &current_node, sizeof(current_node));
    s_statck_index ++;        //

    //Not Finish Work: Top stack check, whether finish work
    while (s_statck_array[s_statck_index - 1].value_7L != CONTAINER_TARGET)    
    {
        //Not the error last operation
        while (s_statck_array[s_statck_index - 1].operation < E_OPERATION_ERROR
            && JudgeTopNodeValid (s_statck_array[s_statck_index - 1]) != 1)
        {
            s_statck_array[s_statck_index - 1].operation ++;
        }

        //Error operation, there is no valid operation can be excuted, so pop stack
        //Pop stack
        if (s_statck_array[s_statck_index - 1].operation >= E_OPERATION_ERROR)
        {
            s_statck_array[s_statck_index].value_3L = 0;
            s_statck_array[s_statck_index].value_7L = 0;
            s_statck_array[s_statck_index].operation = IN_3L;
            s_statck_index --;

            if (s_statck_index == 0)
                return;
            
            //Previous top stack node, try to use "Next operation"
            s_statck_array[s_statck_index - 1].operation ++;
        }
        else
        {
            OperateResult (s_statck_array[s_statck_index - 1], &current_node);
            current_node.operation = IN_3L;
            
            memcpy(&s_statck_array[s_statck_index], &current_node, sizeof(current_node));
            s_statck_index ++;
        }
        
    }

    total = GetStackTotalWater ();
    if (s_total_min > total)
    {
        s_total_min =  total;
    }
    
    printf ("Finish work: s_total_min = %d \n", s_total_min);
    return;     
}
#endif





 

 

0 0