这个是根据网上给的代码整理出来的 :

题目:

一个农夫带着—只狼、一只羊和—棵白菜,身处河的南岸。他要把这些东西全部运到北岸。他面前只有一条小船,船只能容下他和—件物品,另外只有农夫才能撑船。如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。请求出农夫将所有的东西运过河的方案。

理解:

Python农夫过河方案 农夫过河编程_结构体指针

// 宏定义
#define MAXNUM 100
// 定义一个函数指针, 名字叫做DataType
typedef int DataType;

// 写结构体的作用是为了把字符串和所对应的函数建立一种联系, 可以用字符串去找到所对应的函数
// 结构体的声明, 确定结构体里包含的内容
struct SeqQueue {
    DataType q[MAXNUM];
    int f, r; // f是队头, r是队尾
};
typedef struct SeqQueue *pSeqQueue;
// pSeqQueue是一个结构体指针 创建了一个createEmptyQueue_seq的函数
pSeqQueue createEmptyQueue_seq(void) {
    pSeqQueue paqu;
    // mallco 是指你要开辟的对内存空间大小, 在()里面写的是字节数目
    // 通过malloc函数开辟了(struct SeqQueue)这么大小的堆内存空间, 并且返回内存的首地址 为了使用这段内存, 把首地址保存在了一个指针变量paqu中
    // sizeof 是判断数据类型或者表达式长度符
    paqu = (pSeqQueue)malloc(sizeof(struct SeqQueue));
    // 如果paqu这个值是空的, 则直接打印"不在这段空间中"
    if (paqu == NULL) {
        printf("Out of space !!\n");
    } else {
        // -> 结构体指针特殊访问方式
        // 结构体指针 -> 成员变量  (->这个符号叫做指向操作符)
        paqu -> f = 0;
        paqu -> r = 0;
    }
    return (paqu);
}

int isEmptyQueue_seq(pSeqQueue paqu) {
    // 判断两个值是不是相等
    return (paqu ->f == paqu -> r);
}
// 是循环队列进队
// 两个参数, 一个是pSeqQueue  第二个是DataType
void enQueue_seq(pSeqQueue paqu, DataType x) {
    // 算法
    if ((paqu ->r + 1) % MAXNUM == paqu ->f) {
        printf("Full queue.\n");
    } else {
        paqu -> q[paqu ->r] = x;
        paqu -> r = (paqu ->r + 1) % MAXNUM;
    }
}

void deQueue_seq(pSeqQueue paqu) {
    if (paqu -> f == paqu -> r) {
        printf("Empty Queue.\n");
    } else {
        paqu ->f = (paqu ->f + 1) % MAXNUM;
    }
}
// 创建一个DataType类型的函数指针
DataType frontQueue_seq(pSeqQueue paqu) {
    return (paqu -> q[paqu -> f]);
}

// 所谓的确定位置, 就像图片说的, 给一个坑, 找到对应的位置
// & 后面的数字指的就是4个实物的位置, 用二进制标示即为
// 农夫 : 1000
// 野狼 : 0100
// 蔬菜 : 0010
// 山羊 : 0001
int farmer(int location) {
    return (0 != (location & 0x08));
}

int wolf(int location) {
    return (0 != (location & 0x04));
}

int cabbage(int location) {
    return (0 != (location & 0x02));
}

int goat(int location) {
    return (0 != (location & 0x01));
}
// 定义一个函数, 根据位置判断三者的安全问题, 如果不安全返回的是0, 如果安全则返回1
int safe(int location) {
    if ((goat(location) == cabbage(location)) && (goat(location) != farmer(location))) {
        return (0);
    }
    if ((goat(location) == wolf(location)) && (goat(location) != farmer(location))) {
        return (0);
    }
    return (1);
}
// 创建一个无返回值, 无参数的函数
void framerRiverProblem() {
    // 创建三个整型的变量
    int movers, location, newLocaton;
    // 标示一个整型的一维数组
    // 类型说明符 + 数组名[常量表达式\元素的个数]
    int route[16]; // 记录已考虑状态的路径
    // 创建一个变量
    pSeqQueue moveTo;
    // 进行赋值
    moveTo = createEmptyQueue_seq();
    enQueue_seq(moveTo, 0x00);
    // 进行遍历 使得route的第一个值是0, 其他的值都被赋值为-1.
    for (int i = 0; i < 16; i++) {
        route[i] = -1;
    }
    route[0] = 0;
    //!isEmptyQueue_seq(moveTo)"/" && (route[15] == -1)    "/": 类似断句的方式, 将过程断开
    while (!isEmptyQueue_seq(moveTo) && (route[15] == -1)) {
        // 赋值与执行函数
        location = frontQueue_seq(moveTo);
        deQueue_seq(moveTo);
        // movers <<= 1 等价于 a <<= 0, 表示为a左移n位(二进制中)  公式: a * 2 的n次方
        for (movers = 1; movers <= 8; movers <<= 1) { // 农夫总是在移动, 随农夫移动的也只能是与农夫同侧的东西
            // 进行两次判断, 判断位置的变化, 判断过河的情况
            if ((0 != (location  & 0x08)) == (0 != (location & movers))) {
                newLocaton = location^(0x08 | movers);
                if (safe(newLocaton) && (route[newLocaton] == -1)) {
                    route[newLocaton] = location;
                    enQueue_seq(moveTo, newLocaton);
                }
            }
        }
    }
    //判断最后一个元素是不是与我们赋值的-1是相等的
    if (route[15] != -1) {
        printf("The reverse path is:\n");
        // 判断四个事物在和的对面情况, 输出位置的情况
        for (location = 15; location >= 0; location = route[location]) {
            printf("The location is %d \n", location);
            // 判断河的这边最开始的情况
            if (location == 0) {
                return;
            }
        }
    } else {
        // 没有解决的办法
        printf("No solution.\n");
    }
}