题目连接:点击打开链接
题目大意:输入三个字符串,s1, s2, s3,每个字符串只含有大写英文字母组成,并且每个英文字母代表一个特定的数字,然后求 s1 _ s2 = s3; 有多少种解法
注意数字无前导零,然后分母不为0, 第一组测试样例: 1 * 1 = 1; 1 / 1 = 1 ; 0 + 0 = 0 ; 0 - 0 = 0 ; 0 * 0 = 0;
解题思路:因为每个串的长度不超过8,并且这三个串中最多不超过5个字符,所以可以用暴力列举所有的可能的数字情况,然后再进行判断整理
暴力枚举运用DFS进行,很巧妙,有生成全排列(A)的方法,不知道有没有生成随机自由组合(C)的方法;
代码:
//HDU 3699暴力搜索
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
map<char, int> mp, dl; //数字对应, 位置对应
char s1[10], s2[10], s3[10];
char s[30];
int ans;
int flag[10];
int vis[100];
int l;
void cal()
{
int a = 0, b = 0, c = 0;
for(int i = 0; i < strlen(s1); i++)
a = a * 10 + mp[s1[i]];
for(int i = 0; i < strlen(s2); i++)
b = b * 10 + mp[s2[i]];
for(int i = 0; i < strlen(s3); i++)
c = c * 10 + mp[s3[i]];
if(a + b == c) ans++;
if(a * b == c) ans++;
if(a - b == c) ans++;
if(b && a == b*c) ans++; //b不为0, 并且a = b * c
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void dfs(int num)
{
if(num == l)//当num达到l长度的时候,就开始计算,也就是全部分配完的时候开始计算
{
cal();
return ;
}
for(int i = 0; i < 10; i++) //9个数字中选择
{
if(i == 0 && dl[s[num]] == 1) continue; //保证首位不为0
if(flag[i] == 0)
{
flag[i] = 1; //保证在每一次循环里的排列数字是不重复的,
mp[s[num]] = i;
dfs(num+1);
flag[i] = 0; //随机排列,相当于每一次用完之后在进行清零初始化处理
}
}
}
//********************************************************************************
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
ans = 0;
memset(vis, 0, sizeof(vis));
memset(flag, 0, sizeof(flag));
mp.clear(); dl.clear();
ans = 0;
scanf("%s %s %s", s1, s2, s3);
if(strlen(s1) > 1) dl[s1[0]] = 1;
if(strlen(s2) > 1) dl[s2[0]] = 1;
if(strlen(s3) > 1) dl[s3[0]] = 1; //三个字符串首字母所对应的位置都为1
l = 0;
for(int i = 0; i < strlen(s1); i++)
{
if(vis[s1[i]-'A'] != 0) continue;
vis[s1[i]-'A'] = 1;
s[l++] = s1[i];
}
for(int i = 0; i < strlen(s2); i++)
{
if(vis[s2[i]-'A'] != 0) continue;
vis[s2[i]-'A'] = 1;
s[l++] = s2[i];
}
for(int i = 0; i < strlen(s3); i++)
{
if(vis[s3[i]-'A'] != 0) continue;
vis[s3[i]-'A'] = 1;
s[l++] = s3[i];
}
dfs(0);
printf("%d\n", ans);
}
return 0;
}