回 帖 发 新 帖 刷新版面

主题:[原创]就解猜数字问题(谁都会!)完美正式版

/************************************************************************
文件名:    解猜数字题
文件描述:  就解猜数字题
创建人:    陈泽丹,   2006年5月3日, (好惨,五一长假还忍不住心痒要编下程序,呵)
版本号:    1.0
修改次数:
************************************************************************/
/*-----------------------------------------------------------------------
问题描述:
随机给出一个数位上的数字不重复的四位数,让你猜,计算机每次给你提示这样的格
式的语句:xAyB (0<=x<=4, 0<=y<=4)
其中A表示数字正确位置也正确的,B表示数字正确位置不正确。
例如说: 1A2B  (表示1个数字正确位置也正确的,另有两个数字正确位置不正确)
现要求你编程尽可能在7次机会内猜出这个四位数。

解题思路:
把它分两步进行,1,先求这个四位数。2,再求这个四位数各位的
位置。另外,请注意,这两步是互相独立的子问题,故是可以同时进行解决的.

(好累,睡觉先了. 这么热心,要是还不能成精华贴, 那就太失人心喽,呵呵:)  )
------------------------------------------------------------------------*/
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
程序使用说明:
先对程序输入你第一次对游戏猜的那四个数.
再把游戏第一次的提示结果(A+B的和)告诉程序.
之后按程序说的办.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include <iostream.h>
#include <iomanip.h>

const int times=15;                            //总的次数(可变动数值范围)
const int Max=10;                              //可选的数字
const int len=4;                               //数字的选择量
const int tot=210;                             //组合情况的总数
const int position_cord=24;                    //每组数字的排列情况总数
const int position_Max=4;                      //每次待排数字总量
const int position_len=4;                      //每次排的数字量
int number[1][Max];                            //组合设为二维数组以便日后改进
int cord[len];                                 //记录求组合时的中间变量
int total[tot][len];                           //用于记录组合数
int maybe[tot];                                //用于记录可能是答案的组合
int sum[tot];                                  //用于记录所有组合的结果
int p=0;                                       //total的一维指针
int pmaybe=0;                                  //maybe的一维指针
int count=0;                                   //对任意组合的数量进行统计
int guess[times][len];                         //记录每次猜的数字
int pguess=0;                                  //guess的一维指针
int A[times];                                  //记录每次游戏的A指示
int position[position_Max];                    //待排变量
int position_case[position_cord][position_len];//待排情况
int pcase=0;                                   //情况指针

void Init()
{
    p=0;
    pmaybe=0;
    count=0;
    pguess=0;
    pcase=0;
}

void Init_guess()
{
    for (int i=0; i<times; i++)
    {
        for (int j=0; j<len; j++)
            guess[i][j]=-1;
        A[i]=-1;
    }
}

void Init_maybe()
{
    for (int i=0; i<tot; i++)
        maybe[i]=-1;
    pmaybe=0;
}

void Init_number()
{
    for (int i=0; i<Max; i++)
        number[0][i]=0;
}

void set(int m, int n)
{
    int i;
    if (m == len )
    {
        for (i=0; i<len; i++)
            total[p][i]=cord[i];
        count++;
        p++;
    }
    else if ( n < Max)
    {
        for (i=0; i<2; i++)
        {
            if (i==0) { cord[m]=n; set(m+1,n+1); }
            else set(m,n+1);
        }
    }
}

void order(int n)
{
    int i, temp;
    if (n == position_len)
    {
        for (i=0; i<position_len ;i++)
            position_case[pcase][i]=position[i];
        pcase++;
    }
    else
    {
        for (i=n; i<position_Max; i++)
        {
            temp=position[n]; position[n]=position[i]; position[i]=temp;
            order(n+1);
            temp=position[n]; position[n]=position[i]; position[i]=temp;
        }
    }
}

void condition(int sum, int pnum)
{
    int sumk;
    int temp;
    Init_maybe();
    for (int i=0; i<tot; i++)
    {
        sumk=0;
        for (int j=0; j<len; j++)
        {
            temp=total[i][j];
            sumk+=number[pnum][temp];
        }
        if (sumk == sum) { maybe[pmaybe]=i; pmaybe++; }
    }
}

int answer(int sum, int pnum)
{
    condition(sum, pnum);
    pmaybe=0;
    int i=0,j=0;
    int temp;
    while(1)
    {
        if (maybe[pmaybe] == -1) break;
        i=maybe[pmaybe];
        for (j=0; j<len; j++)
        {
            temp=total[i][j];
            cout<<temp<<" ";
        }
        cout<<endl;
        pmaybe++;
    }
    if (pmaybe >= 1) return 1;
    return 0;
}

void sum_fun(int pnum)
{
    int sumk, temp;
    for (int i=0; i<tot; i++)
    {
        sumk=0;
        for (int j=0; j<len; j++)
        {
            temp=total[i][j];
            sumk+=number[pnum][temp];
        }
        sum[i]=sumk;
    }
}

void set_number(int(* a)[len], int line)
{
    int i, temp;
    for (i=0; i<Max; i++)
        number[0][i]=number[0][i]*10;
    for (i=0; i<len; i++)
    {
        temp=a[line][i];
        if (pguess < times ) guess[pguess][i]=a[line][i];
        number[0][temp]++;
    }
    pguess++;
}

int position_order(int n, int pguess)
{
    if (pguess>=0)
    {
        int c=0;
        for (int i=0; i<len; i++)
            if ( position_case[n][i] == guess[pguess][i]) c++;
        if (c == 4) return 0; 
        if (c > A[pguess]) return 0;
        return position_order(n,pguess-1);
    }
    else return 1;
}

int set_maybe(int sum)
{
    condition(sum, 0);
    int i=0, right=0;
    int k=0;
    for (pmaybe=0; pmaybe<tot; pmaybe++)
    {
        i=maybe[pmaybe];
        for (int po=0; po<position_len; po++)
            position[po]=total[i][po];
        pcase=0;
        order(0);
        for (right=0; right<position_cord; right++)
            if ( position_order(right,pguess-1) ) {  k=1; break; }
        if ( k==1 ) break;
    }
    if (pmaybe == tot) { cout<<"该题目无解"<<endl; return 0; }
    set_number(position_case, right);
    cout<<"请向游戏输入:";
    for (int kk=0; kk<len; kk++)
        cout<<position_case[right][kk]<<" ";
    cout<<endl;
    return 1;
}

void first()
{
    int a[1][len], limit=0;
    while(limit<len)
    {
        cout<<"请输入你第一次猜时的第"<<limit+1<<"个数字:";
        cin>>a[0][limit];
        if (a[0][limit] >=0 && a[0][limit]<Max) limit++;
        else cout<<"输入数字不在范围内,请重输!"<<endl;
    }
    set_number(a, 0);
}


int fun()
{
    Init();
    Init_guess();
    Init_number();
    Init_maybe();
    first();
    int b=0;
    int result=0;
    set(0,0);
    cout<<"总组合情况: "<<count<<endl;

    cout<<"请输入游戏的第一次时A的提示情况:";
    cin>>A[pguess-1];
    if (A[pguess-1] == 4) 
    { 
        cout<<"\n谢谢使用本程序!"<<endl;
        return 1;
    }
    cout<<"请输入游戏的第一次时B的提示情况:";
    cin>>result;
    result=result+A[pguess-1];
    b=b*10+result;
    cout<<"第一次提示情况下可能的组合:"<<endl;
    for (int kk=2; kk<=times; kk++)
    {
        if (!answer(b,0) ) { cout<<"该题目无解"<<endl; break; }
        cout<<endl;
        set_maybe(b);

        cout<<"请输入游戏的第"<<kk<<"次的A的提示情况:";
        cin>>A[pguess-1];
        if (A[pguess-1] == 4) break;

        cout<<"请输入游戏的第"<<kk<<"次的B的提示情况:";
        cin>>result;
        result=result+A[pguess-1];
        b=b*10+result;
        cout<<"第"<<kk<<"次提示情况下可能的组合:"<<endl;
    }
    cout<<"\n谢谢使用本程序!"<<endl;
    return 1;
}

void main()
{
    cout<<"程序名:  解猜数字游戏."<<endl;
    cout<<"程序描述:解猜数字游戏(模拟人的逻辑解题)"<<endl;
    cout<<"创建人:  陈泽丹.   (完成时间:2006年5月3号凌晨4点54分)"<<endl;
    cout<<"QQ:       82314038"<<endl;
    cout<<"\n大家可以上这个网址:http://home.kele8.com/flashgame/showgame.asp?id=10139"<<endl;
    cout<<"测试程序运行效果。程序游戏偶就不写了,要程序游戏是偶写,解程序的也是偶写,难免有投机"<<endl;
    cout<<"之嫌, 呵呵."<<endl;
    cout<<"\n题外话:  欢迎组队开发软件! ( 好了,快天光了,呵呵,该是偶睡觉的时侯了:) 各位早安 )"<<endl;
    cout<<"---------------------------------------------------------------------------------------------------"<<endl;
    char a;
    do
    {
        fun();
        cout<<"若输入#退出本程序:";
        cin>>a;
        cout<<endl<<endl;
    }while (a != '#');
}

回复列表 (共37个回复)

11 楼

楼主我把我的程序稍微改了以下,在每次输入的后面加了一个判断数字是否重复的函数,重复报错,但是对于程序控制的我没有来得及设计.估计再次来得时候又要是周末了,所以先把先把这份不完全的代码贴上,也请楼主再提点意见,
对于我的食言,我很抱歉!

12 楼

#include <conio.h>

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#include <string.h>

#include <process.h>

#define N 10

#define SIZE 4

int ScanNum(char const *str);

char Instruct(void);

char creatnum(char *str);

int guess(char const *str);

int scannum(char const *str);

char menu();

int main()
{
    char string[SIZE];
    srand(time(NULL));
    creatnum(string);
    printf("%s", string);
    while( guess(string) );
      
    
    getchar();    
    return 0;        
}

char menu()
{
    char ch;
    printf("玩一盘: P \n");
    printf("离开:     q \n");

    
    scanf("%c", &ch);
    return ch;
}

int scannum(char const *str)
{
    int i, j;
    for(i = 0; i < SIZE; ++ i)
        for(j = i + 1; j < SIZE; ++ j){
            if(str[i] == str[j]){
                printf("输入错误,请重试! \n");
                return 1;
            }
        }
      return 0;    
}

int guess(char const *str)
{
    char str1[SIZE];
    int A = 0, B = 0, cnt = 0, i, j;
    char ch;
    ch = menu();
    if(  ch  == 'q' || ch == 'Q')
        exit(1);
    
    while(cnt < N){ 
        A = 0; 
        B = 0;
        printf("请输入一个不重复的四位数:");
    
        scanf("%s", str1);
        if( scannum(str1) )
            continue;
        else{
            for(i = 0; i < SIZE; ++ i)
                for(j = 0; j < SIZE; ++ j)
                    if(str[i] == str1[j])
                        ++ B;
            
            for(i = 0; i < SIZE; ++ i)
                if(str[i] == str1[i])
                    ++ A;                                                   
        }
        if(A == 4){
            printf("恭喜! 你猜对了!");
             
            return 1;
        }
        else
            printf("A%dB%d\n", A, B - A);
           ++ cnt;    
    }
    printf(" 对不起! 你输掉了! \n");
    return 0;
   
}

char creatnum(char *str)
{
    //产生一个随即数 
    int a, b, c, d, rad;

    // 产生一个各位不数字不重复的四位数
    
    do
        a = rand() % 10;
    while(a == 0);
    do 
        b = rand() % 10;
    while(b == a);
    do
        c = rand() % 10;
    while(c == b || c == a);
    do 
        d = rand() % 10;
    while(d == c || d == b || d == a);
    
    rad = 1000 * a + 100 * b + 10 * c + d;
    itoa(rad, str, 10); //数字转换成字符串 
    return 0;
}


在dev-cpp下重写的;

13 楼

没什么食言不食言啦, 只是一道题而已啦, 不必挂怀.^-^

哈,偶很仔细的看了你的代码.写得很不错,接近完美啦.从思路到程序结构,纠错检查.但这点还不算很棒,在先头部队遭受创击的情况下,第二击重甲上阵还是可以的,难能可贵的是你第二次的编程风格,空行,对齐,注释, 函数声明等,都用上了正规作战了.哈哈,这点我十分欣赏, 思路简单明了, 而且程序也长得漂亮, 看来是有备而来的.呵呵.
可惜一主题最多加50分, 没分加喽.

最后,偶还是爱鸡蛋里挑骨头下,呵呵.
为什么要把数字转为字符串呢,既然是猜数字,用数字为类型不更直接有效些?
不过从长远看,字符形有可扩展的空间,这个方法掌握熟,运用上是一利.
最后细心检查结果,程序合格的且优质产品.哈.

14 楼

我最初的想法是转换成字符串为了更好确定A,B的值.现在想来用数字也没有什么不可以的.
我把我的程序的控制的流程又做了以下修改,这下基本没有问题了.在vc 6.0,dev-cpp,以及lcc-win32下均运行通过.也贴上来请楼主在看看,我不怎么在意分数,只要学到了东西就行. 共勉!



#include <conio.h>

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#include <string.h>

#include <process.h>

#define N 10

#define SIZE 4

int ScanNum(char const *str);

char Instruct(void);

char creatnum(char *str);

void guess(char const *str);

int scannum(char const *str);

char menu();

int main()
{
    char static string[SIZE];
    char ch;
    
    srand(time(NULL));
    

    
    for(;;){
        creatnum(string);
    //    printf("%s", string);
        ch = menu();
        if (ch == 'p' || ch == 'P')
               guess(string);
        if (ch == 'q' || ch == 'Q')
            exit(0);
        getchar();
    }
     
    getchar();    
    return 0;        
}

char menu()
{
    char ch;
    printf("玩一盘: P \n");
    printf("离开:     q \n");    
    scanf("%c", &ch);
    return ch;
}

int scannum(char const *str)
{
    //对数入的数字进行扫描,如果有相同的数字,报错退出 
    int i, j;
    for(i = 0; i < SIZE; ++ i)
        for(j = i + 1; j < SIZE; ++ j){
            if(str[i] == str[j]){
                printf("输入错误,请重试! \n");
                return 1;
            }
        }
      return 0;    
}

void guess(char const *str)
{
    //猜10次数,中途猜对可提前退出 
    char str1[SIZE];
    int A, B, cnt = 0, i, j;

    while(cnt < N){ 
        A = 0; 
        B = 0;
        printf("请输入一个不重复的四位数:");
    
        scanf("%s", str1);
        if( scannum(str1) ){
               continue;    
        }
        else{
            for(i = 0; i < SIZE; ++ i)//确定包含正确数字的个数 
                for(j = 0; j < SIZE; ++ j)
                    if(str[i] == str1[j])
                        ++ B;
            
            for(i = 0; i < SIZE; ++ i)//确定位置正确的数字个数 
                if(str[i] == str1[i])
                    ++ A;                                                   
        }
        if(A == 4){
            printf("恭喜! 你猜对了!");             
            return;
        }
        else
            printf("A%dB%d\n", A, B - A);  //确保A、B所指内容不重复 
           ++ cnt;    
    }
    printf(" 对不起! 你输掉了! \n");
    return;   
}

char creatnum(char *str)
{
    //产生一个随即数 
    int a, b, c, d, rad;

    // 产生一个各位不数字不重复的四位数
    
    do
        a = rand() % 10;
    while(a == 0);
    do 
        b = rand() % 10;
    while(b == a);
    do
        c = rand() % 10;
    while(c == b || c == a);
    do 
        d = rand() % 10;
    while(d == c || d == b || d == a);
    
    rad = 1000 * a + 100 * b + 10 * c + d;
    itoa(rad, str, 10); //数字转换成字符串 
    return 0;
}

15 楼

完美的猜数字游戏是人随机想出一个数字让电脑来猜

16 楼

第一楼的程序实现的就是让电脑来猜啊
sjyf老兄的程序实现的是让电脑随机出一个数.

合起来,就是让电脑随机出一个数,再让电脑来猜...
呵,这怎么有点像周伯通的左右互搏之术----详见神雕侠侣.

17 楼

没细看,但感觉楼上各位的配比部分算法效率不高.
我的算法: 单层循环,关键的配比部分

for(i = 0; i < 4; i++)
{
  if(string1[i] == string2[i/4])     {A++; contiune;}//位置及数都正确
  if(string1[i] == string2[(i+1)/4]) {B++; contiune;}//数正确但位置不对
  if(string1[i] == string2[(i+2)/4]) {B++; contiune;}
  if(string1[i] == string2[(i+3)/4]) {B++; contiune;}
}

18 楼

不太明白你的意思...

在我的程序里并没有这里的所谓的配比部份,因为我在分治法后,根本就不用这种一个数字一个数字位置与值比较的方法.

其次,不好意思,弱弱的指出一下,上面的程序并没有提高多少效率,因为它只是用另一部方法把内循环里的执行部分全部一行行写出来而已...
另外可读性也变弱了些,程序的可扩充性也变弱了...

19 楼

既然题目是:随机给出一个数位上的数字不重复的4位数,楼主一再强调的可扩展性也就是四行和十行的关系.
理论上单层循环的大O = n,多层是 O=n*n...

20 楼

可能你有些误会我的意思了,我并没有一再强调可扩充性啊,那是另外一个话题...

是这样啊,可是该理论是相对于执行过程的规模而言的.
如果把那可循环的一条条写出来的,它还是数量级的时间复杂度的,因为它的执行过程并没变,只是写法上不同而已.

说的直白且不严密一点,在你的单层循环里,所有的if语句合起就是一个内层循环,当程序的规模扩大了,比方说猜5个数,且不说你要添加语句,就执行过程而言,同样是"内层循环"多了一遍.也就是说,当程序规模扩大时,以上程序的时间复杂度还是n*n.

我来回复

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