问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

求狼羊白菜过河的C语言编程题详解。希望不要用数组解决。

发布网友 发布时间:2023-03-09 16:04

我来回答

1个回答

热心网友 时间:2023-10-11 11:54

按照你的要求,不使用数组。

我的思路,起点货物狼、羊、白菜,人一直在开船,通过递归函数,每次靠岸尝试装卸货方案,直到找满足条件的方案。将可行方案存放在结构链表中形成操作流水打印。

人狼羊菜存储方式模拟4位2进制,用1111表示,每位表示一个单位,1存在,0不存在。

#include<stdio.h>
#include<malloc.h>
typedef enum{false,true}bool;
typedef struct opRecord//用结构链表记录操作流水
{
    int p1_take;//p1载货值
    int p1_goAd;//p1卸货值
    int p2_take;//p2载货值
    int p2_goAd;//p2卸货值
    int cen;//递归层号
    struct opRecord *next;
}OPR;
OPR *oprHead;
OPR *oprTail;
char *getName(int b);//获取对应名称
int beEaten(int p1,int p2);//检查是否发生被吃事件,发生返回1,未发生返回0
int toShip(int *p1,int *p2,int *ship,bool f);//递归函数:上船人及任意一组合,返回状态,1:方案可行;0:方案不可行
int getFist(int pn);//获取物品组合中第一个
void addLog(int p1_take,int p1_goAd,int p2_take,int p2_goAd,int cen);//将有效操作添加进日志,cen相同,将视为修改覆盖
void printfLog();//打印操作流水
OPR *findLogBycen(int cen);//通过cen查找流水。 有返回节点指针。无返回NULL

int count=1;
int flag=0;//标识变量=1成立;  =0不成立
int cen=0;
int main()
{
    int p1=111,ship=1000,p2=0000;//p1,p2分别表示两岸,4位数每一位分别表示人狼羊菜,位数值1表示存在,0表示不存在
    oprHead=(OPR *)malloc(sizeof(OPR));
    oprHead->next=NULL;
    oprTail=NULL;
    printf("河岸有人、狼、羊、白菜要过河,船每次载人及一物,为避免人上船后狼吃羊或羊吃菜\n开始生成方案:\n\n");
    if(toShip(&p1,&p2,&ship,0))
    {
        printf("\n开始生成结果报告:\n");
        printfLog();
    }
    else
        printf("无可行方案!!\n");
    return 0;
}
void addLog(int p1_take,int p1_goAd,int p2_take,int p2_goAd,int cen)//将有效操作添加进日志,cen相同,将视为修改覆盖,
{
    OPR *oprNew=findLogBycen(cen);
    if(oprNew==NULL)//通过查找。确认无记录,新增记录
    {
        oprNew=(OPR *)malloc(sizeof(OPR));
        oprNew->p1_take=p1_take;
        oprNew->p1_goAd=p1_goAd;
        oprNew->p2_take=p2_take;
        oprNew->p2_goAd=p2_goAd;
        oprNew->cen=cen;
        oprNew->next=NULL;
        if(oprHead->next==NULL)
            oprHead->next=oprNew;
        else
            oprTail->next=oprNew;
        oprTail=oprNew;
    }
    else//查找发现已有记录,修改
    {
        oprNew->p1_take=p1_take;
        oprNew->p1_goAd=p1_goAd;
        oprNew->p2_take=p2_take;
        oprNew->p2_goAd=p2_goAd;
    }
}
OPR *findLogBycen(int cen)//通过cen查找流水。 有返回节点指针。无返回NULL
{
    OPR *headSave=oprHead;
    while(headSave->next!=NULL)
    {
        if(headSave->next->cen==cen)
            return headSave->next;
        headSave=headSave->next;
    }
    return NULL;
}
void printfLog()//打印操作流水
{
    OPR *headSave=oprHead;
    int p1_take,p1_goAd,p2_take,p2_goAd,cen,p1TOp2,p2TOp1;
    while(headSave->next!=NULL)
    {
        p1_take=headSave->next->p1_take;
        p1_goAd=headSave->next->p1_goAd;
        p2_take=headSave->next->p2_take;
        p2_goAd=headSave->next->p2_goAd;
        cen=headSave->next->cen;
        if(p1_take>0 || p1_goAd>0)
            p1TOp2=1;
        else
            p1TOp2=0;
        if(p2_take>0 || p2_goAd>0)
            p2TOp1=1;
        else
            p2TOp1=0;
        printf("操作流水%2d:",cen);
        printf("%s%s",p1TOp2>0?"从p1":"",p2TOp1>0?"从p2":"");
        printf("%s%s",p1_goAd>0?getName(p1_goAd):"",p1_goAd>0?"下船":"");
        printf("%s%s",p1_take>0?getName(p1_take):"",p1_take>0?"上船":"");
        printf("%s%s",p2_goAd>0?getName(p2_goAd):"",p2_goAd>0?"下船":"");
        printf("%s%s",p2_take>0?getName(p2_take):"",p2_take>0?"上船":"");

        if(headSave->next->next!=NULL)
            printf("。之后行驶方向:%s%s\n",p1TOp2>0?"p1->p2":"",p2TOp1>0?"p1<-p2":"");
        else
            printf("\n");
        headSave=headSave->next;
    }
}
char *getName(int b)//获取对应名称
{
    if(b==1000)
        return "人";
    else if(b==100)
        return "狼";
    else if(b==10)
        return "羊";
    else if(b==1)
        return "菜";
    return "";
}
int toShip(int *p1,int *p2,int *ship,bool f)//递归函数:上船人及任意一组合;lastTake:上一次承载物体,首次调用传0;f=0:p1->p2方向;1:反向。返回状态,1:方案可行;0:方案不可行;
{
    int take=-1,goAd,gdflag=1,cenSave;//take:上船物体。  goAd:下船物体。gdflag:标识变量,p2判断能否直接下船,1能0不能
    cenSave=++cen;
    while(1)
    {
        goAd=*ship-1000;
        if(f==0)//准备p1往p2
        {
            if(take==-1)
                take=getFist(*p1);
            *p1-=take;
            *p1+=goAd;
            gdflag=1;//标识置1,等到p2首先尝试直接卸货
        }
        else//准备p2往p1
        {
            if(take==-1 && gdflag==0)
            {
                take=getFist(*p2);
                printf("开始尝试替换货物:\n");
            }
            if(gdflag==1)//如果p2可以直接卸货
                *p2+=goAd;
            else//如果不能直接卸货,尝试带走一个同时卸货
            {
                *p2-=take;
                *p2+=goAd;
            }
        }
        printf("递归层级%d:假设%s从%s上船。%s下船,%s方向行驶。\n",cenSave,take>0?getName(take):"无货物",f==0?"p1":"p2",goAd!=0?getName(goAd):"无货物",f==0?"p1往p2":"p2往p1");

        if(beEaten(*p1,*p2))//如果发生被吃,假设失败,还原数据,选择下一假设
        {
            if(f==0)
            {
                *p1+=take;
                *p1-=goAd;
            }
            else
            {
                if(gdflag==1)//p2点确定不能直接卸货,还原数据,标识置0
                {
                    printf("----不能直接卸货,货物%s回到船上。",getName(goAd));
                    *p2-=goAd;
                    gdflag=0;
                    continue;
                }
                else//不能直接卸货并尝试替换货物失败,选择下一个货物替换
                {
                    *p2+=take;
                    *p2-=goAd;
                }
            }
            if(take==1)
            {
                printf("本次靠岸无可行的装卸方案,返回层级%d!\n",cenSave-1);
                return 0;
            }
            take=take/10;//尝试选择下一个货物
            continue;
        }
        else
        {

            if(f==1 && gdflag==1)//p2直接卸货假设成立船清空
                *ship=1000;
            else
                *ship=1000+take;//换货假设成立货物装船
            if(*p1==0)//如果已经完全转移
            {
                printf("所有货物过河成功!!\n");
                return 1;
            }
            if(f==0)
                addLog(take,goAd,0,0,cenSave);//生成流水日志
            else
                addLog(0,0,take,goAd,cenSave);//生成流水日志
            if(toShip(p1,p2,ship,f==0?1:0))
            {
                return 1;
            }
            else//由于下级失败,本回合重新选择
            {
                gdflag=0;
                continue;
            }
        }
    }
}
int getFist(int pn)//获取物品组合中第一个
{
    int i,count=0;
    while(1)//上船物体从岸上第一个物体开始选择
    {
        if(pn<=1)
            break;
        pn=pn/10;
        count++;
    }
    for(i=0;i<count;i++)
        pn=pn*10;
    return pn;
}
int beEaten(int p1,int p2)//检查是否发生被吃事件,发生返回1,未发生返回0
{
    int ren=0;
    if(p1==110 && ++ren==1)
        printf("----河岸p1狼把羊吃了!重新选择\n");
    if(p2==110 && ++ren==1)
        printf("----河岸p2狼把羊吃了!重新选择\n");
    if(p1==11 && ++ren==1)
        printf("----河岸p1羊把菜吃了!重新选择\n");
    if(p2==11 && ++ren==1)
        printf("----河岸p2羊把菜吃了!重新选择\n");
    return ren;
}

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
圣斗士星矢正义传说攻略_圣斗士星矢正义传说新手攻略 圣斗士星矢正义传说怎么觉醒圣衣 圣衣玩法攻略 圣斗士星矢正义传说召唤石怎么获得 获取攻略一览 超市促销员手机上打卡迟到几分钟 在超市里打卡显示的公司是什么意思? 长鹿休闲度假农庄交通指南 求从容桂到长鹿农庄怎么坐车,详细,准确 形容神情的五字词语 女生内衣穿多久该扔掉 吴江离张家港有多远? 暖心表白情话(精选50句) 表白情话短句(热门60句) 2023年安全员考试时间公布,看看有你所在的省份吗!? 什么是陪读生? 什么是世界三大宗教,还有什么宗教呢? 罐装八宝粥可以放微波炉加热吗? 怎么解封不需要好友辅助? 爵士鼓和架子鼓有什么不一样 ps抠头发丝最简单方法 黄瓜炒鸡蛋怎么做的 春节祝福同事及单位祝福语 大话西游2,地宫140级卓越怎么杀? 梦见光头的男人是什么意思 大话西游二2转110队伍怎么杀地宫 《大话西游2》120-139级卓越地宫怎么杀? 大话2地宫怎么杀 进门就是餐厅和客厅怎么设计鞋柜 派克服兔毛内胆怎么洗 南北 二三四五 六七八九 是什么意思? 二三四五六七八六九是什么意思 如何让云企业网支持路由 8月:夏天结束了 女生夏天已经过去一大半了怎么回复 背影[bèi yǐng]什么意思?近义词和反义词是什么?英文翻译是什么? 汉白玉大象雌雄的区别 2022年8月30日是祭奠吉日吗 2022年农历八月初四宜祭奠吗 山药之乡在那里 21款英朗上的软件可以卸载吗 清白自守文言文翻译 米线如何炒才好吃 俄罗斯产三彩石吗 俄罗斯三彩金是什么 什么降血糖 小米手机为什么不能下载荔枝云集 荔枝FM用手机下载有时失败 药房营业时间pop 两种牛里脊的美味吃法讲解 地板起鼓后能恢复吗 曲面显示器适合作图吗 曲面屏用来画cad有影响吗?