回 帖 发 新 帖 刷新版面

主题:做了个算24点牌的C程序,另求算“猜数字”思想

先说“猜数字”,是不是最少7步?

//以下为24点程序//
//    +    -    *    /    --    -/
//    0    1    2    3    4    5

#include<stdio.h>
#include<math.h>

int treat(float a,float b,float c,float d);
float myF(int flag,float m,float n);
void myPrint(int type,int i,int j,int k,float a,float b,float c,float d);

int time,temp=0;
void main()
{
    int i,j,k,t,again,res,flag;
    float num[4];
    again=1;
    while(again==1)
    {
        printf ("\nPlease Enter 4 nums(1~13):\n");
        i=0;
        flag=0;
        while (flag==0)
        {
            i++;
        //    printf ("Input num-%d\n",i);
            for(i=0;i<4;i++)
            {
                scanf("%f",&num[i]);
                if (num[i]<1 || num[i]>13 || num[i]!=int(num[i]))
                    flag++;
            }
            if(flag!=0)
            {
                printf ("Error input again\n",i);
                flag=0;
            }
            else
                flag=1;
        }
        for (i=0;i<4;i++)
            for (j=0;j<4;j++)
                if (j!=i)
                    for (k=0;k<4;k++)
                        if (k!=j && k!=i)
                            for (t=0;t<4;t++)
                                if (t!=i && t!=j && t!=k)
                                {
                                    res=treat(num[i],num[j],num[k],num[t]);
                                }
    if (res==0)
        printf ("\nNo answer\n");
    else ;
    //    printf ("time=%d\n\n",time);
    printf ("\n1: Go on\n2: Quit\n");
    scanf ("%d",&again);
    }
}

int treat(float a,float b,float c,float d)
{
    int i,j,k;
    float sum1,sum2,sum3;
    for (i=0;i<4;i++)
        for (j=0;j<6;j++)
            for (k=0;k<6;k++)
            {
                if ((!(i==3 && b==0)) && (!(j==3 && c==0)) && (!(k==3 && d==0)))
                {
                    sum1=myF(i,a,b);
                    sum2=myF(j,sum1,c);
                    sum3=myF(k,sum2,d);
                    if (fabs(sum3-24)<0.1)
                    {
                        temp++;
                        myPrint(1,i,j,k,a,b,c,d);
                    //    printf ("sum1:myF(%d,%2.0f,%2.0f)  sum1=%f\n",i,a,b,sum1);
                    //    printf ("sum2:myF(%d,%2.0f,%2.0f)  sum2=%f\n",j,c,d,sum2);
                    //    printf ("1:myF(%d,myF(%d,myF(%d,%2.0f,%2.0f),%2.0f),%2.0f)   sum3=%f\n\n",k,j,i,a,b,c,d,sum3);
                    }
                }
                if (k==2)
                {
                    sum1=myF(i,a,b);
                    sum2=myF(j,c,d);
                    sum3=sum1*sum2;
                     if (fabs(sum3-24)<0.1)
                    {
                        temp++;
                        myPrint(2,i,j,k,a,b,c,d);
                    //    printf ("sum1:myF(%d,%2.0f,%2.0f)  sum1=%f\n",i,a,b,sum1);
                    //    printf ("sum2:myF(%d,%2.0f,%2.0f)  sum2=%f\n",j,c,d,sum2);
                    //    printf ("2:myF(%d,myF(%d,%2.0f,%2.0f),myF(%d,%2.0f,%2.0f))   sum3=%f\n\n",k,i,a,b,j,c,d,sum3);
                    }
                }

                if (k==3)
                {
                    sum1=myF(i,a,b);
                    sum2=myF(j,c,d);
                    if (sum2!=0)
                    {
                        sum3=sum1/sum2;
                         if (fabs(sum3-24)<0.1)
                        {
                            temp++;
                            myPrint(3,i,j,k,a,b,c,d);
                        //    printf ("sum1:myF(%d,%2.0f,%2.0f)  sum1=%f\n",i,a,b,sum1);
                        //    printf ("sum2:myF(%d,%2.0f,%2.0f)  sum2=%f\n",j,c,d,sum2);
                        //    printf ("3:myF(%d,myF(%d,%2.0f,%2.0f),myF(%d,%2.0f,%2.0f))   sum3=%f\n\n",k,i,a,b,j,c,d,sum3);
                        }
                    }
                }
            }
    if (temp==0)
        return 0;
    else
        return 1;
}

float myF(int flag,float m,float n)
{    
//    time++;
    if (flag==0)
        return (m+n);
    if (flag==1)
        return (m-n);
    if (flag==2)
        return (m*n);
    if (flag==3)
        if (n==0)
            return 30000;
        else
            return (m/n);
    if (flag==4)
        return (n-m);
    if (flag==5)
        if (m==0)
            return 30000;
        else
            return (n/m);
    return 0;
}

void myPrint(int type,int i,int j,int k,float a,float b,float c,float d)
{
    char sigle[6];
        sigle[0]='+';
        sigle[1]='-';
        sigle[2]='*';
        sigle[3]='/';
        sigle[4]='-';
        sigle[5]='/';
    if (type==1){
        if(j==4 || j==5)
        {
            if (k==4 || k==5)
                printf("%2.0f %c (%2.0f %c (%2.0f %c %2.0f)) =24\n",d,sigle[k],c,sigle[j],a,sigle[i],b);
            else
                printf("(%2.0f %c (%2.0f %c %2.0f)) %c %2.0f =24\n",c,sigle[j],a,sigle[i],b,sigle[k],d);
        }
        else if (k==4 || k==5)
        {
            printf("%2.0f %c ((%2.0f %c %2.0f) %c %2.0f) =24\n",d,sigle[k],a,sigle[i],b,sigle[j],c);
        }
        else
            printf("((%2.0f %c %2.0f) %c %2.0f) %c %2.0f =24\n",a,sigle[i],b,sigle[j],c,sigle[k],d);
    }
    if (type==2 || type==3)
    {
    //    if (k==4 || k==5)
    //        printf("(%2.0f %c %2.0f) %c (%2.0f %c %2.0f)=24\n",c,sigle[j],d,sigle[k],a,sigle[i],b);
    //    else
            printf("(%2.0f %c %2.0f) %c (%2.0f %c %2.0f) =24\n",a,sigle[i],b,sigle[k],c,sigle[j],d);
    }
}                    

回复列表 (共57个回复)

31 楼

求教
哪位高人有新算法求猜数字

32 楼

这个猜数字的游戏规则是怎样的?
mAnB   表示什么?

33 楼

这是文曲星上的游戏

34 楼

不知道具体的规则,所以也不知道是不是这个样的。
这个第几步的说法是不是和我下面所说一样?

穷举5040个数字的结果是:

第0次猜出个数:1      //这个数是就是9876,固用这个数作第一次比较

第1次猜出个数:12

第2次猜出个数:109

第3次猜出个数:584

第4次猜出个数:1598

第5次猜出个数:1822

第6次猜出个数:781

第7次猜出个数:125

第8次猜出个数:7  


#include "stdio.h"
#include "conio.h"
void Del_Sum_flag(int a,int b,char *string);
void Set_Sum();
char* Get_Sum(char *string);
#define Sum_Max  5040
struct sum
{
char a;
char b;
char c;
char d;
int flag;
};
struct sum temp[Sum_Max];
main()
{
   int t=0;
   char tem[5],*ptr,c;
   int A,B;

   for(;;)
   {

    Set_Sum();

    clrscr();

    for(;;)
    {
     ptr=Get_Sum(tem);

     printf(" %d  是这个吗?     %s     Yes/No?",t+1,ptr);
     scanf(" %c",&c);
     if (c=='y')break;

     printf("\n数字对有几个?         A=");
     scanf(" %d",&A);
     printf("\n数字对位置对有几个?   B=");
     scanf(" %d",&B);

     Del_Sum_flag(A,B,ptr);
     t++;
     }
    t=0;
    printf("\n还玩吗?");
    scanf(" %c",&c);
    if (c!='y')exit(1);
  }
}

void Set_Sum()
{ int a,b,c,d,t=0;

  for(a='0';a<='9';a++)
  for(b='0';b<='9';b++)
  if(b!=a)
  for(c='0';c<='9';c++)
  if(c!=b&&c!=a)
  for(d='0';d<='9';d++)
   if(d!=c&&d!=b&&d!=a)
   {temp[t].a=a;
    temp[t].b=b;
    temp[t].c=c;
    temp[t].d=d;
    temp[t].flag=1;
    t++;
   }
}
void Del_Sum_flag(int a,int b,char *string)
{  int i=Sum_Max-1,a0=0,b0=0,t;
   char *ptr;

   while(i>=0)
   {  if (temp[i].a==*string)b0++;
      if (temp[i].b==*(string+1))b0++;
      if (temp[i].c==*(string+2))b0++;
      if (temp[i].d==*(string+3))b0++;
      ptr=string;
      t=0;
      while(t<4)if(*(ptr+t)==temp[i].a){a0++;break;}
                  else t++;
      ptr=string;
      t=0;
      while(t<4)if(*(ptr+t)==temp[i].b){a0++;break;}
                   else t++;
      ptr=string;
      t=0;
      while(t<4)if(*(ptr+t)==temp[i].c){a0++;break;}
                   else t++;
      ptr=string;
      t=0;
      while(t<4)if(*(ptr+t)==temp[i].d){a0++;break;}
                  else t++;

      if(a0!=a||b0!=b)temp[i].flag=0;
      a0=0;
      b0=0;
    i--;
   }
}
char* Get_Sum(char *string)
{ int i=Sum_Max-1;

while(i>=0){
     if (temp[i].flag==1)
      {
      *string=temp[i].a;
      *(string+1)=temp[i].b;
      *(string+2)=temp[i].c;
      *(string+3)=temp[i].d;
      *(string+4)='\0';
      return string;
      }
      i--;
      }

printf("错误!肯定是你的错!!不是我猜错!!! ^_^");
exit(1);
}

35 楼

你能说一下你的算法吗?
要七次之内,而且没有第0次的说法,也就是说你还有7个数要第9次才能猜中.

要有0个数8次或8次以上猜中,在上面的我用pascal做的可以实现7次之内,
但我希望能有更好的算法用c做也可以.

36 楼

我的算法很简单,先设置一个5040个数的数组(我用结构体),从最大的数开始选取一个作猜测数(即打印出来的数),得到A,B的值后,将数组中所有的数与猜测数作比较,AB值不同的删除(标上作废记号),再从未删除的数中取最大的数(我试尝过取最小的,或者两头交换取,统计结果差不多,但最后被取出的数有变化。这中间的规律我还没有搞清。)

你上面的算法我看了,我的机子差,不能用你的方法去找最佳猜测数,5040个数猜一轮回都要5分钟。
你所说的分类我看不太明白,能否细说?我看了看用我的程序最后猜测出来的数好象有一定的规律。

37 楼

分类:第一次试猜后会得到很多个AB的值,可以对0A1B进行寻找最佳的第二次试猜的数(这时候第三次和以后的还是按归律,我每次取的是剩下的最小的数),第二次的最佳答案找到了就看哪些数还需要8次才能猜出来,而这些数在第二次的最佳数试猜时产生什么效果,对不同的效果再进行分类,找最佳的第三次试猜,依次下去最后没有数需要8次来猜就结束了.
(我最开始找一类要用10个多小时.我运行了几天发现按照我的想法,要找的数还多着哩,后来我进行适当的处理,只要几十秒或几分钟我记不清了,我的问题才有得解决)

前两次为0A1B和0A2B的最难猜,我是找到了第五次试猜的最佳试猜数,才使得没有数需要8次.
我在剩下的数中每次都取最小的,和你取最大的没有本质的区别.
我觉得第一次就应该找到最佳试猜数,而不一定就是0123.
总感觉用某种递归可以让有最少的数在7次被猜中,让最少的数在6次被猜中,让最少的数在5次被猜中,也就是我想找到平均试猜次数的最小值

7楼说:
5步之内猜中的概率可达到55.8%
6步之内猜中的概率可达到97.5%
不知道他说的是真是假
我是达不到
我6步好像可以达到88%多,5步好像不到50%.
我总觉得应该用某种递归来解决这个问题,而不是找一大堆的实实在在的数.

38 楼

这个是我今天写的猜数字的程序
请大家多多指教
在VC++6。0上编译通过
并且运行正常


//stdafx.h


#include <stdlib.h>
#include <time.h>
#include <iostream.h>

void Create_digit(int *&);
int Is_exized(int *,int);
void Guess(int *);
void Istrue(int *,int *,int &,int &);


//stdafx.cpp

#include "stdafx.h"


void Create_digit(int * &dnum)
{
    int stime,n=0,i=0;
    long ltime;
    ltime=time(NULL);
    stime=(unsigned)ltime/2;
    srand(stime);
    
    dnum=new int[4];
    dnum[0]=0;
    
    do
    {
        do
        {
            n=rand()%10;
        }while(n==0);

        if( Is_exized(dnum,n)==0 )
            dnum[i]=n;
        else
            continue;
        i++;
    }while(i<4);                 //生成无重复数字的四位整数

}

void Guess(int *dnum)
{
    int counta,countb,num,*n;
    
    for(int i=1;i<=10;i++)
    {
        counta=0;
        countb=0;               //每一次循环清一次0

        cout<<"请输入一个4位数!!"<<endl;
        cin>>num;
        
        n=new int[4];
        for(int j=3;j>=0;j--)
        {
            n[j]=num%10;
            num/=10;
        }
        
        Istrue(dnum,n,counta,countb);
        
        switch(counta)
        {
        case 4:cout<<"你真聪明!!"<<endl;exit(1);
        default:cout<<counta<<"A"<<countb<<"B"<<endl;break;
        }    
    }    
    
    cout<<"正确结果为:"<<endl;
    for(int k=0;k<4;k++)
        cout<<dnum[k];
    cout<<endl;
    
}



void Istrue(int *dnum,int *n,int & counta,int & countb)
{
    int i,j;
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            if( dnum[j]==n[i] && i==j)             //位置和数字都相同
                counta++;    
            else if( dnum[j]==n[i] && i!=j)       //位置不同,数字相同
                countb++;
        }                                //位置和数字均不同,则什么也不做
    }
}



int Is_exized(int *dnum,int n)     //判断重复数字
{
    for(int i=0;i<4;i++)
    {
        if(dnum[i]==n)
            return 1;
    }

    return 0;
}


//主函数

#include "stdafx.h"

int main(int argc, char* argv[])
{

    int *dnum;

    Create_digit(dnum);
    Guess(dnum);


    return 0;
}

39 楼

哈哈!!!
关于猜数字我最近又有了新算法简直是个飞越!!!
比7楼说的还神!
我5次可以猜中57.59%
  6次可以猜中97.62%
  7次可以猜中100%
具体情况如下:
第1次猜出个数:1      //在新算法中第一个试猜数(也就是第一个被猜中的数)取任
                      //何一个数对整个程序都没有影响,我习惯取0123
第2次猜出个数:3

第3次猜出个数:49

第4次猜出个数:485

第5次猜出个数:2365

第6次猜出个数:2017

第7次猜出个数:120

平均步数只有约为5.33步

2楼说:“我的意思是有没有可能用更少的步数?
         路边看得的消息说外国有5步的神话”
我可以给出证明所有的数都在5步或5步之内猜出是不可能的!
但是不是所有的数都可以在6步或6步之内猜出我就不知道了,
但我正在为之而努力我最开始有654个数需要7次来猜,而现在只有120个数需要7次来猜。
我不知道还会不会有更好的结果。
卖个“关子”,想知道具体算法的敢快跟贴呀!!!
或者想和我一起讨论关于猜数字的也可以跟贴或加我qq.



40 楼

大哥门,拜托代码给点注释好不好

我来回复

您尚未登录,请登录后再回复。点此登录或注册