描述、思路
補充知識
參考2:C語言條件編譯及編譯預處理階段
參考3:C++技巧之斷言Assert
實現
使用條件編譯,解決不同問題時選擇性註釋一下條件編譯#define ISGOOGLE指令即可分別解決不同問題:
“WWWDOT - GOOGLE = DOTCOM” ——》 #define ISGOOGLE
“AAB – BBC = CCD” —————————》 //#define ISGOOGLE(註釋掉即可)
#include <iostream>
#include <cassert>
// 條件編譯
// #define ISGOOGLE 未被註釋掉時,表示求解google equation問題
// #define ISGOOGLE 被註釋掉時,表示求解secret equation問題
//#define ISGOOGLE
const int max_number_count = 10;
#ifdef ISGOOGLE
const int max_char_count = 9;
#else
const int max_char_count = 4;
#endif //ISGOOGLE
/*字母三元組*/
struct CharItem
{
char c; // 字母
int value; // 數值
bool leading; // 是否爲開頭
};
/* 數值二元組 */
struct CharValue
{
bool used; // 是否被使用
int value; // 數值
};
/* 回調函數指針(回調判斷本次分配的字母數值組合是否滿足方程) */
typedef void (*CharListReadyFuncPtr)(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);
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;
}
#ifdef ISGOOGLE
/* 檢查本次分配的字母數值是否滿足等式,若滿足則打印 */
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;
}
#else
/* ABCD問題:檢查本次分配的字母數值是否滿足等式,若滿足則打印 */
void CharListReady(CharItem ci[max_char_count])
{
char* minuend = "AAB";
char* subtrahend = "BBC";
char* diff = "CCD";
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;
}
#endif // ISGOOGLE
/* 核心: 爲字母三元組數組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;
}
void solve()
{
/* 數值二元組初始化 */
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}
};
#ifdef ISGOOGLE
std::cout << "Solve Google Equation \"WWWDOT - GOOGLE = DOTCOM\" : " << std::endl;
/* 字母三元組初始化 */
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}
};
#else
std::cout << "Solve Secret Equation \"AAB – BBC = CCD\" : " << std::endl;
/* 字母三元組初始化 */
CharItem char_item[max_char_count] =
{
{'A',-1,true}, {'B',-1,true}, {'C',-1,true}, {'D',-1,false}
};
#endif //ISGOOGLE
SearchingResult(char_item, char_val, 0, CharListReady);
return;
}
int main()
{
// 代碼頂部#define ISGOOGLE,表示求解GOOGLE方程問題
// 代碼頂部#define ISGOOGLE被註釋掉時,表示求解Secret方程問題
solve();
return 0;
}
運行結果
每次編譯、運行時改變的源碼頂部以及運行效果如圖: