穷举搜索:Google方程式

来源:互联网 发布:linux tomcat部署项目 编辑:程序博客网 时间:2024/04/29 08:08

有一个由字符组成的方程式:WWWDOT-GOOGLE=DOTCOM 每一个字母代表一个不同的数字,不能以0开头。

使用穷举法就是对每个字母用0~9的数字尝试10次,由于没一个字母代表不同的数字,如果考虑0开头的情况,这样的组合有10*9*8*7*6*5*4*3*2*1=3628800组合。

数据结构的定义上,要避免固定9个字符的方法,就需要定义一可变化的字符元素列表,每个字符包含3个属性:

struct CharItem
{
    char c;         // 字母
    int value;      // 数值
    bool leading;   // 是否为开头
};

由于这是一个组合问题,两个字母不能被指定为相同的数字,这样需要对每个数字做一个标示,当这个数字被占用时,其他就不可以使用此数字,结构体为:

struct CharValue
{
    bool used;      // 是否被使用
    int value;      // 数值
};

穷举算法采用递归方式进行枚举,按照CharItem列表的顺序,对每个字符进行数字遍历,算法实现如下:

/* 核心: 为字母三元组数组ci分配数值二元组中的可能的数值组合,
  index标志分配到的字母编号,从0开始 */
void SearchingResult(CharItem ci[max_char_count],
                     CharValue cv[max_number_count],
                     int index, CharListReadyFuncPtr callback)//为返回函数,当返回时调用此函数;
{
    //为所有字符分配完数值,若是解则打印,然后返回上一层
    if(index == max_char_count)
    {
        callback(ci);//检查ci是否是符合等式的字符组合,若符合则打印
        return;
    }
    //每层递归要遍历所有未使用的数字
    for(int i = 0; i < max_number_count; ++i)
    {
        // 检查能否分配该数字,检查数字是否使用、字母是否是开头字母
        if(IsValueValid(ci[index], cv[i]))
        {
            //穷举赋值
            cv[i].used = true;
            ci[index].value = cv[i].value;
            //继续下层递归
            SearchingResult(ci, cv, index + 1, callback);
            //继续同层遍历
            cv[i].used = false;
        }
    }
    return;
}

根据题目要求W、G、D不能为0,对这三个字符进行剪枝操作,用I是valueVlid()作为评估函数,callback函数被调用的次数减少到30%,callback函数的编写

void CharListReady(CharItem ci[max_char_count])
{
    char* minuend    = "WWWDOT";
    char* subtrahend = "GOOGLE";
    char* diff       = "DOTCOM";


    int m = MakeIntegerValue(ci, minuend);
    int s = MakeIntegerValue(ci, subtrahend);
    int d = MakeIntegerValue(ci, diff);
    if((m - s) == d)
    {
        std::cout << m << " - " << s << " = " << d << std::endl;
    }
    return;
}

/* 回调函数指针(回调判断本次分配的字母数值组合是否满足方程) */
typedef void (*CharListReadyFuncPtr)(CharItem ci[max_char_count]);//void CharListReady(CharItem ci[max_char_count])声明这个函数的指针


/* 从字母三元组数组ci中,找到字符c对应的指向三元组的指针 */
CharItem* GetCharItem(CharItem ci[max_char_count], char c)
{
    for(int i = 0; i < max_char_count; ++i)
    {
        if(ci[i].c == c)
        {
            return &ci[i];
        }
    }
    return NULL;
}


/* 判断是否可以为ci中的字母分配cv中的数字 */
bool IsValueValid(CharItem ci, CharValue cv)
{
    if(cv.used)
    {
        return false;
    }
    if(ci.leading && (cv.value == 0))
    {
        return false;
    }
    return true;
}


/* 根据字母三元组ci的分配,计算字符串chars对应的整数值 */
int MakeIntegerValue(CharItem ci[max_char_count], char* chars)
{
    assert(chars);//assert宏的原型定义在<assert.h>中,其作用是,则终止程序执行给其一个参数,即一个断言为真的表达式,若果断言不为真则发送一个错误信息告诉断言是什么,以及失败之后,程序终止
    int value = 0;
    char* p = chars;
    while(*p)
    {
        CharItem* char_item = GetCharItem(ci, *p);//得到了一个结构体的对象这样可以通过->符号来取得值
        if(char_item == NULL)
        {
            return 0;
        }
        value = value* 10 + char_item->value;
        p++;
    }
    return value;
}

int main()
{
    /CharValue char_val[max_number_count] =
    {
        {false,0}, {false,1}, {false,2}, {false,3},
        {false,4}, {false,5}, {false,6}, {false,7},
        {false,8}, {false,9}
    };

CharItem char_item[max_char_count] =
    {
        {'W',-1,true}, {'D',-1,true}, {'O',-1,false},
        {'T',-1,false}, {'G',-1,true}, {'L',-1,false},
        {'E',-1,false}, {'C',-1,false}, {'M',-1,false}
    };

SearchingResult(char_item, char_val, 0, CharListReady);/
    return 0;
}

0 0