动物识别系统的规则库

一、题目

这是一个用以识别虎、金钱豹、斑马、长颈鹿、企鹅、鸵鸟、信天翁七种动物的产生式系统。为了实现对这些动物的识别,该系统建立了如下规则库:

  • R1: IF 该动物有毛     THEN 该动物是哺乳动物
  • R2: IF 该动物有奶     THEN 该动物是哺乳动物
  • R3: IF 该动物有羽毛   THEN 该动物是鸟
  • R4: IF 该动物会飞     AND 该动物会下蛋   THEN 该动物是鸟
  • R5: IF 该动物吃肉    THEN 该动物是食肉动物
  • R6: IF 该动物有犬齿   AND 有爪 AND 眼盯前方  THEN 该动物是食肉动物
  • R7: IF 该动物是哺乳动物 AND有蹄 THEN 该动物是有蹄类动物
  • R8: IF 该动物是哺乳动物 AND该动物是反刍动物 THEN 该动物是有蹄类动物
  • R9: IF 该动物是哺乳动物 AND是食肉动物 AND黄褐色 AND 暗斑点 THEN 该动物是豹
  • R10:IF 该动物是哺乳动物 AND 食肉动物 AND黄褐色 AND 黑色条纹 THEN 该动物是虎
  • R11:IF 该动物是有蹄类动物 AND 有长脖子 AND 有长腿 AND 有暗斑点 THEN 该动物是长颈鹿
  • R12:IF 该动物是有蹄类动物 AND 有黑色条纹 THEN 该动物是斑马
  • R13:IF 该动物是鸟 AND 不会飞 AND 有长脖子 AND 有长腿 AND 有黑白二色 THEN 该动物是鸵鸟
  • R14:IF 该动物是鸟 AND 不会飞 AND 会游泳 AND 有黑白二色 THEN 该动物是企鹅
  • R15:IF 该动物是鸟 AND 善飞 THEN 该动物是信天翁

二、实现过程

  最开始我就是直接通过给出的判决条件,用简单的if…else语句来实现这个推理系统,直接给出所有的判决条件,让用户输入,而用户未知的条件让用户进行否决,但是这样会带来问题,比如说会飞、会下蛋可以退出是鸟类动物,但是如果我已知是鸟类了,再去推导企鹅的过程中就会否定之前的条件,因为企鹅有一个不会飞,和之前的会飞推出的是鸟类产生冲突。所以可以先画出推理图,进行层次划分,如下图所示:
推理过程图
图中括号后的数字可以忽略,这个是我第一个版本的判决条件的编号。通过这个推理图,可以简单的将整个推理过程分为两大部分,其中的哺乳动物和食肉动物可以组成一个部分,鸟类单独作为一个部门,另外,值得注意的是,食肉动物不能单独推出金钱豹和虎,但是哺乳动物可推出斑马,这在这个图中容易引起读者的错误思考。

三、代码

#include<stdio.h>

int main() {
    printf("\n\n=====动物识别系统=====\n\n");
    printf("判决条件:\n");
    printf(" 1. 有毛         2.有奶            3.有羽毛          4.会飞          5.会下蛋     6.眼盯前方\n");
    printf(" 7. 有蹄         8.反刍动物        9.吃肉           10.有犬齿        11.有爪     \n");
    printf("12.长脖子       13.长腿            14.暗斑点        15.有黑色条纹\n");
    printf("16.黄褐色       17.不会飞          18.黑白二色      19.会游泳         20.善飞\n");
    printf("\n请输入已知条件序号(如2,输入999结束。):\n");
    const int num = 20; //条件个数
    int inputs[num] = { 0 };
    int i = 0;
    while (i < num) {
        int temp;
        scanf_s("%d", &temp);
        if (temp == 999) break;
        if (temp < 1 || temp >20) {
            printf("序号有误,请重新输入: \n");
            continue;
        }
        inputs[i] = temp;
        i++;
    }
    int sign[num] = { 0 };  //标志每一个条件(有就标志为1,没有就标志为0)
    int bf[num] = { 0 };  //用于备份
    int j = 0;
    while (inputs[j] != 0) {
        sign[inputs[j] - 1] = 1;
        bf[inputs[j] - 1] = 1;
        j++;
    }
    if (sign[0] || sign[1]) {
        // 满足哺乳动物条件
        if (bf[0]) {
            printf("\n使用规则:有毛--->哺乳动物\n");
        }
        else {
            printf("\n使用规则:有奶--->哺乳动物\n");
        }
        sign[0] = 0, sign[1] = 0;
        //printf("=====该动物是哺乳动物=====\n\n");
        if (sign[6] || sign[7]) {
            // 满足有蹄类动物条件
            if (bf[6]) {
                printf("\n使用规则:哺乳动物+有蹄--->有蹄类动物\n");
            }
            else {
                printf("\n使用规则:哺乳动物+反刍动物--->有蹄类动物\n");
            }
            sign[6] = 0, sign[7] = 0;
            //printf("=====该动物是有蹄类动物=====\n\n");
            if (sign[11] && sign[12] && sign[13]) {
                sign[11] = sign[12] = sign[13] = 0;
                printf("\n使用规则:有蹄类动物+有长脖子+有长腿+有暗斑点--->长颈鹿\n");
                printf("\n\n======该动物是长颈鹿======\n\n");
            }
            else if(sign[14]){
                sign[14] = 0;
                printf("\n使用规则:有蹄类动物+有黑色条纹--->斑马\n");
                printf("\n\n======该动物是斑马======\n\n");
            }
            else {
                printf("\n\n======无法具体判断=====\n\n");
            }
        }
        else if (sign[8] || (sign[5] && sign[9] && sign[10])) {
            if (sign[8]) {
                printf("\n使用规则:吃肉--->食肉动物\n");
            }
            else {
                printf("\n使用规则:有犬齿+有爪+眼盯前方--->食肉动物\n");
            }
            sign[8] = sign[5] = sign[9] = sign[10] = 0;
            // 满足食肉动物条件
            //printf("=====该动物是食肉动物=====\n\n");
            if (sign[13] && sign[15]) {
                sign[13] = sign[15] = 0;
                printf("\n使用规则:食肉动物+哺乳动物+黄褐色+有暗斑点--->金钱豹\n");
                printf("\n\n======该动物是金钱豹======\n\n");
            }
            else if (sign[14] && sign[15]) {
                sign[14] = sign[15] = 0;
                printf("\n使用规则:食肉动物+哺乳动物+黄褐色+黑色条纹--->虎\n");
                printf("\n\n======该动物是虎======\n\n");
            }
        }
        else {
            printf("\n\n======无法具体判断=====\n\n");
        }
    }
    else if (sign[2] || (sign[3] && sign[4])) {
        // 满足鸟类条件
        if (sign[2]) {
            printf("\n使用规则:有羽毛--->鸟类\n");
        }
        else {
            printf("\n使用规则:会飞+会下蛋--->鸟类\n");
        }
        sign[2] = 0, sign[3] = 0, sign[4] = 0;
        //printf("\n\n=====该动物是鸟类=====\n\n");
        if (sign[11] && sign[12] && sign[16] && sign[17]) {
            sign[11] = sign[12] = sign[16] = sign[17] = 0;
            printf("\n使用规则:鸟类+有长脖子+有长腿+不会飞+有黑白二色--->鸵鸟\n");
            printf("\n\n======该动物是鸵鸟======\n\n");
        }
        else if (sign[16] && sign[17] && sign[18]) {
            sign[16] = sign[17] = sign[18] = 0;
            printf("\n使用规则:鸟类+会游泳+不会飞+有黑白二色--->企鹅\n");
            printf("\n\n======该动物是企鹅======\n\n");
        }
        else if (sign[19]) {
            sign[19] = 0;
            printf("\n使用规则:鸟类+善飞--->信天翁\n");
            printf("\n\n======该动物是信天翁======\n\n");
        }
        else {
            printf("\n\n======无法具体判断=====\n\n");
        }
    } 
    else {
        printf("\n\n======无法具体判断=====\n\n");
    }
    int xx = 0; //标记
    for (int i = 0; i < num; i++) {
        if (sign[i]) {
            printf("\n\n推理最可能动物时,存在多余条件, 序号是 %d\n",i+1);
            xx = 1;
        }
    }
    if (xx == 1) printf("\n\n=======以上推理失效=======\n");
}

代码中的bf数组,是用于存放用户输入条件的备份数组,因为原始的数组在后期一旦经过判断,就将这个条件置0,也就是不能再使用了,另外最后一个标记循环,只能说是在已经进入第二层或者第三层 的情况下,给出了多余的条件,这个循环才会生效,不然测试一种失败条件时很可能所有的条件都会直接给出。

四、总结

  通过本次对动物识别系统的规则库的实现,对产生式系统的机制如推理方式等等有了一个基本的了解和认识。在对程序的改进过程中,弥补了最开始逻辑的漏洞,以及最开始仅仅是根据题目直接用if…else语句进行推导,到后来做出推理图,才真正对题目有了较为深刻的理解,对用户暂时还没有输入的条件进行全盘否定的做法进行了改正,并且在最后将具体的推理过程展现给用户。这不仅是对上课所学的内容有了基本巩固,同时,对此类题目出现的逻辑思维和程序设计思想也有了进一步的提升。这是一个简单的if…else语句实现,读者可以根据自己的需要进行修改。

  • 18
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亲爱的老吉先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值