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

(爱问答)

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

可以画一下流程图么

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

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

人狼羊菜存储方式模拟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("河岸有人、狼、羊、白菜要过河,船每次载人及一物,为避免人上船后狼吃羊或羊吃菜 开始生成方案: ");
   if(toShip(&p1,&p2,&ship,0))
   {
       printf(" 开始生成结果报告: ");
       printfLog();
   }
   else
       printf("无可行方案!! ");
   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 ",p1TOp2>0?"p1->p2":"",p2TOp1>0?"p1<-p2":"");
       else
           printf(" ");
       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("开始尝试替换货物: ");
           }
           if(gdflag==1)//如果p2可以直接卸货
               *p2+=goAd;
           else//如果不能直接卸货,尝试带走一个同时卸货
           {
               *p2-=take;
               *p2+=goAd;
           }
       }
       printf("递归层级%d:假设%s从%s上船。%s下船,%s方向行驶。 ",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! ",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("所有货物过河成功!! ");
               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狼把羊吃了!重新选择 ");
   if(p2==110 && ++ren==1)
       printf("----河岸p2狼把羊吃了!重新选择 ");
   if(p1==11 && ++ren==1)
       printf("----河岸p1羊把菜吃了!重新选择 ");
   if(p2==11 && ++ren==1)
       printf("----河岸p2羊把菜吃了!重新选择 ");
   return ren;
}


相关标签:c语言

下一篇:求助检查:Xas.java:1:错误:需要

上一篇:javaspcrit

热门标签:
excel 网盘 破解 word dll
最新更新:
微软重新评估新的Outlook的使用时机 联想推出搭载联发科Helio G80芯片组的Tab M9平板 英特尔创新大赛时间确定! 微软Edge浏览器在稳定渠道中推出Workspaces功能 英伟达RTX4060TiGPU推出MaxSun动漫主题! 谷歌地图为用户提供了街景服务! GameSir 在T4 Kaleid中推出了一款出色的控制器! 微软开始在Windows 11 中测试其画图应用程序的新深色模式! LG电子推出全球首款无线OLED电视 英伟达人工智能芯片崭露头角! Steam Deck可以玩什么游戏-Steam Deck价格限时优惠 雷蛇推出CobraPro鼠标 Kindle电子阅读器可以访问谷歌商店吗 Windows10如何加入组策略 window10图片查看器怎么没有了?