采用回溯法。首先把解空间树设成5层strlen(str)叉树,然后深度优先搜索这棵树,如果遍历发现正在遍历的结点所代表的的字母已经在current[]中,则剪枝,否则把该节点存进current[]里面。遍历到叶子结点时,首先判断current[]里面的字母是否满足题意,如果不满足则回溯,如果满足则判断该字典序是否大于原来已经找到的best[],如果是则把best[]的内容替换为current[]的,否则回溯。
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
const int M = 100;
const int N = 100;
char best[6] = { '\0' };
char current[6] = { '\0' };
bool is_in_str(char c, char str[], int n) //判断c是否在str[]里面
{
for (int i = 0; i < n; i++)
{
if (str[i] == c)
return true;
}
return false;
}
void traceback(int n, char str[], int t)
{
if (t == 5) //到达解空间树的叶子结点
{
int s = 0;
for (int i = 0; i < 5; i++)
{
s += (int)(pow(current[i] - 'A' + 1, i + 1) * pow(-1, i));
}
if (s == n)
{
if (best[0] == '\0' || strcmp(best, current) < 0) //如果所得到的解的字典序比原来best[]存储的要大,则best[]存储这个解
{
strcpy(best, current);
}
}
}
else if (t < 5)
{
for (unsigned int i = 0; i < strlen(str); i++)
{
if (!is_in_str(str[i], current, t)) //所得到的解里面不能有重复字母
{
current[t] = str[i];
traceback(n, str, t + 1);
current[t] = '\0';
}
}
}
}
int main(void)
{
int n[M] = { 0 };
char str[M][N] = { '\0' };
int check, i, k;
i = 0;
k = 0;
cin >> check;
while (check != 0) //检查输入的n是否为0
{
n[k] = check;
cin >> str[k];
k++;
cin >> check;
}
for (int i = 0; i < k; i++) //对输入的每一行进行计算
{
traceback(n[i], str[i], 0);
if (best[0] == '\0')
cout << "no solution" << endl;
else
cout << best << endl;
for (int j = 0; j < 6; j++) //计算完每一行后要对best[]和current[]重新设为初始值
{
best[j] = '\0';
current[j] = '\0';
}
}
return 0;
}