回 帖 发 新 帖 刷新版面

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

/************************************************************************
文件名:    解猜数字题
文件描述:  就解猜数字题
创建人:    陈泽丹,   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个回复)

21 楼

具体问题具体分析,如果不幸忘了如何嵌套,原代码里一行行写出来也无妨,反正编译出来的obj是一样滴~

22 楼

楼上的说的没错,的却时间复杂度是小了,
n= 4的确无所谓,n大了就有所谓了,
我在开始写的时候也想有单层循环替代,但是没有想起来,佩服!

23 楼

哈,有争议是好事,碰撞才能出智慧的火花.
不过作为一个十分热爱编程的人,为了心中的理想和梦,我不得不打破沙锅问到底.


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;}
}
其实就等价于
for(i=0; i<4; i++)
{
   for(j=0; j<4; j++)
   {
       if (string1[i] == string2[(i+j)/4] ) 
          { 
              if (j==0) A++; else B++;
              break;
          }
    }
}

而之所以说它数量级是n*n, 是因为当规模变大时,它的两层循环是会随着同时变大的,而不是一层循环变大而已.

24 楼

楼主我没有明白你的意思,我觉得:
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;}
}
做了4次循环;
for(i=0; i<4; i++)
{
   for(j=0; j<4; j++)
   {
       if (string1[i] == string2[(i+j)/4] ) 
          { 
              if (j==0) A++; else B++;
              break;
          }
    }
}

做了16次循环,单从循环的次数来说前者是比后者更好的.

楼主指的是什么?说清楚点.

25 楼

这里:
(
  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;}
)
其实就是一个循环啊(你看,在string2里它是从0遍历到3,就是四次喽)
只不过是把内循环一行行写出来而已,不会就认不出它是一个循环吧...
而当增加数的规模,例如说猜5个数,那么它就得变成是这样
(
  if(string1[i] == string2[i/5])       {A++; contiune;}//位置及数都正确
  if(string1[i] == string2[(i+1)/5]) {B++; contiune;}//数正确但位置不对
  if(string1[i] == string2[(i+2)/5]) {B++; contiune;}
  if(string1[i] == string2[(i+3)/5]) {B++; contiune;}
  if(string1[i] == string2[(i+4)/5]) {B++; contiune;}
)
也就是说,他的算法并没有实现猜5个数时,他里面还是
(
  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;}
)//这样四次.

所以它其实就是一个n*n的算法.
所以当猜四个数时,它与两重循环的时间复杂度是一样的.
当猜大于四个数时,它就得相当增加语句,而其最终结果还是两重循环.

是的,从写法上看,好像变成了单层循环.
但事实上从发展的角度来看,一研究执行过程,就会发现在其实都是双重循环,只不过换了个写法.
(顺便一提,时间复杂度O()...这个概念本身就有其发展观的角度,若然不是发展观的意思,那么无所谓O(),而直接写起执行次数好了.)

难道它的意义只局限于:它只能求猜四个数吗? 
若然是这样,那么虽然时间复杂度看起来不同,但其效率是一样的.

若然不是只限于求四个数:
则它必须相应增加检测语句,增加的最后结果还是变成一个内部循环.

好,倘若我们就是不要从发展的角度看这程序的算法!
即就是充许它能且只能求4个数的.
那么其写法看起来是O(n),但的它的内部语句也用了四次啊(共就4(次循环)*4=16次执行过程),而双重循环也是16,效率并不见得提高多少.

直白点说,从算法角度看,它其实就是一个双重循环,只不过把内循环换了个写法.

26 楼

这里可能是因为阅读的观点有一点点不同吧,

我读他的程序时更主要的是看他的算法思路,所以推测他在规模增大了时所需做的措施,从而判断程序的实质其实就是n*n的时间复杂度.

如果单纯从仅限于此题的形式上写法看,确实就是o(n).

[em2]

27 楼

楼主果然深刻,佩服!

28 楼

if (string1[i] == string2[(i+j)/4] ) 
          { 
              if (j==0) A++; else B++; //if (j==i)
              break;
          }

29 楼

又作了次修改.
采用类作法,并增加了一个函数,该函数作用是先猜那些可能情况最少的,有利于更快的排除不可能情况.

文件如下:

30 楼

#ifndef HEADER_GUESS
#define HEADER_GUESS

/************************************************************************
文件名:    解猜数字题
文件描述:  就解猜数字题
创建人:    陈泽丹,   2006年6月6日
版本号:    2.0
修改次数:  2
************************************************************************/
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
程序使用说明:
先对程序输入你第一次对游戏猜的那四个数.
再把游戏第一次的提示结果(A+B的和)告诉程序.
之后按程序说的办.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include <iostream.h>
#include <iomanip.h>
#include <windows.h>
#include <stdlib.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;                      //每次排的数字量

class Guess
{
private:
    int number[1][Max];                                //组合设为二维数组以便日后改进
    int cord[len];                                    //记录求组合时的中间变量
    int total[tot][len];                            //用于记录组合数
    int maybe[tot];                                    //用于记录可能是答案的组合
    int sum[tot];                                    //用于记录所有组合的结果
    int p;                                            //total的一维指针
    int pmaybe;                                        //maybe的一维指针
    int count;                                        //对任意组合的数量进行统计
    int guess[times][len];                            //记录每次猜的数字
    int pguess;                                        //guess的一维指针
    int A[times];                                    //记录每次游戏的A指示
    int position[position_Max];                        //待排变量
    int position_case[position_cord][position_len];    //待排情况
    int pcase;                                        //情况指针
    void Init();
    void Init_guess();
    void Init_maybe();
    void Init_number();
    void set(int m, int n);
    void order(int n);
    int sort();
    void condition(int sum, int pnum);
    int     answer(int sum, int pnum);
    void sum_fun(int pnum);
    void set_number(int(* a)[len], int line);
    int  position_order(int n, int pguess);
    int  set_maybe(int sum);
    void first();
    int  fun();
public:
    Guess();
    void start();
};

inline Guess::Guess():p(0), pmaybe(0), count(0), pguess(0), pcase(0) {}

#endif

我来回复

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