洛谷P1092 虫食算(回溯法)

来源:互联网 发布:视频管理系统php 编辑:程序博客网 时间:2024/06/05 10:49

洛谷P1092 虫食算(回溯法)

题目描述

所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:
http://paste.ubuntu.com/25448822/
其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。
现在,我们对问题做两个限制:
首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。
其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表午的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N-1)。输入数据保证N个字母分别至少出现一次。
http://paste.ubuntu.com/25448824/
上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解

输入输出格式

输入格式:

包含四行。第一行有一个正整数N(N<=26),后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。

输出格式:

包含一行。在这一行中,应当包含唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

输入输出样例

输入样例:

5
ABCED
BDACE
EBBAA

输出样例:

1 0 3 4 2

说明

对于30%的数据,保证有N<=10;
对于50%的数据,保证有N<=15;
对于全部的数据,保证有N<=26。
noip2004提高组第4题

解题分析

基本思路是用回溯法对每一个字母进行枚举(0到n-1),但如不进行剪枝和优化,则肯定有测试用例超时(复杂度O(n!))。
题目分析:共有n个不同的字母,每个字母表示不同的数字(0到n-1);a, b, c的长度相同,因此最高位没有进位。
可以进行如下剪枝和优化:
1、与手工计算加法的方法一样,从个位数开始搜索。为了方便起见,开始先将三个字符串逆序。
2、对每一个字母枚举的顺序为从n-1到0,因为最高位没有进位,这样搜索可以更快地得到结果。
3、在枚举字母时,按照从低位到高位第一次出现的字母的次序进行。这样在回溯时可以更有效率地判断是否进入下一个分支。
4、在判断可以进入下一分支前(假设已经判断到a, b, c的第i个字符),如果在i到最高位之间的某个位置j,a[j],b[j], c[j]都已确定,则判断它们是否合法,如果不合法,则不能进入下一个分支。由于不知道进位,但进位只能是0或1,因此在判断是否合法时,在(a[j]+b[j])%n和(a[j]+b[j]+1)%n这两个数中,如果都不等于c[j],则肯定是不合法的。
5、在对一个字母进行枚举时,如果其第一次出现的在i列,但在i列的其他两个元素都已经知道,则可有由他两个元素的值和进位计算该字母应该是哪个数字,而不需要从0~n逐个枚举。在判断是否可行时,只要判断从i开始向后的各列即可(因为能到i列,说明前面i-1列都合法),由于前i-1列都合法,在判断前i-1列时可以得到每一步的进位数carry[]。要实现该优化,还必须记录每一个字母第一次出现的列数。
6、在判断是否进入下一分支前,如果判断到某列i中有2个字母已确定,则计算第三个字母(进位为carry[i-1])的值,如果该值已经被其他字母占用,则不能进入下一分支。
7、尽量避免采用除法,因为除法的计算时间比其他运算符都要大。
8、由于a, b, c的都是n位,因此,如果最高位进位,则不能进入下一分支。
9、如果得到结果,则尽快退出回溯,可采用flag判断是否已得到结果。

10、尽量不要用STL中的容器,本来打算采用map存储字母和值之间的映射关系,但测试用例9始终TLE,改掉之后一下变为24ms,其他都为0ms。看来容器所增加的复杂度系数不容小觑。

#include #include #include #include #include using namespace std;int n;string a, b, c;int alpha[26], d[26], digit[26], cnt = 0, used[26] = {0}, vis[26] = {0};int order[26], order_i[26], flag = 0; int digit_map[26];// 优化10 char digit_map1[26]; // 优化10char digit_c[26];string reverse(string str){int i, len = str.size();for(i=0; i=0)p1 = p;elsep1 = n + p;        if(used[p1])    return 0;    }else if(vis[i_a] && !vis[i_b] && vis[i_c]){  // 优化6p = digit[i_c] -digit[i_a] - carry1;// 优化7 if(p>=0)p1 = p;elsep1 = n + p;        if(used[p1])    return 0;    }if(!(vis[i_a] && vis[i_b] && vis[i_c])){if(!judge1(i))  // 优化4 return 0;carry[i-1] = carry1;return 1;}p = carry1 + digit[i_a] + digit[i_b];// 优化7 if(p>=n){p1 = p - n;carry1 = 1;}else{p1=p;carry1 = 0;}if(p1!=digit[i_c])return 0;i++;}if(carry1)// 优化8 return 0;if(i==n){for(i=0; in){return;}j = order[depth];i_o = order_i[depth];i_a = digit_map[a[i_o]-'A'], i_b = digit_map[b[i_o]-'A'], i_c = digit_map[c[i_o]-'A'];if(vis[i_a] && vis[i_b] && !vis[i_c]){  // 优化5 p = digit[i_a] + digit[i_b] + carry[i_o-1];    p1 = p%n;    if(!used[p1]){    used[p1] = 1;    digit[j] = p1;digit_map1[p1] = digit_c[j];vis[j] = 1;    if(judge(i_o)){dfs(depth + 1);}    used[p1] = 0;    vis[j] = 0;     }         }else if(!vis[i_a] && vis[i_b] && vis[i_c]){  // 优化5 p = digit[i_c] -digit[i_b] - carry[i_o-1];if(p>=0)p1 = p;elsep1 = n + p;        if(!used[p1]){    used[p1] = 1;    digit[j] = p1;digit_map1[p1] = digit_c[j];vis[j] = 1;    if(judge(i_o)){dfs(depth + 1);}    used[p1] = 0;    vis[j] = 0;     }         }else if(vis[i_a] && !vis[i_b] && vis[i_c]){  // 优化5 p = digit[i_c] -digit[i_a] - carry[i_o-1];if(p>=0)p1 = p;elsep1 = n + p;        if(!used[p1]){    used[p1] = 1;    digit[j] = p1;digit_map1[p1] = digit_c[j];vis[j] = 1;    if(judge(i_o)){dfs(depth + 1);}    used[p1] = 0;    vis[j] = 0;     }            }else {for(i=n-1; i>=0; i--){  // 优化2 if(!used[i]){digit[j] = i;digit_map1[i] = digit_c[j];vis[j] = 1;used[i] = 1;if(judge(i_o)){dfs(depth + 1);}used[i] = 0;vis[j] = 0;}} }}int main(){ios::sync_with_stdio(false);int i;cin>>n;cin>>a>>b>>c;a = reverse(a), b = reverse(b), c = reverse(c); // 优化1 ini();for(i=0; i<26; i++){if(alpha[i]){digit_map[i] = cnt;digit_c[cnt] = i + 'A';order[alpha[i]] = cnt++;// 优化3 }}dfs(1);return 0;}