搜索_DFS_CH2902_虫食算

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84144206

点此打开题目页面

思路分析:

    从相加的最低两位开始考察, 注意利用已知两个数可求第三个数进行剪枝. 注意在下面的AC代码中第59, 68和77行的i值如果从0开始递增会TLE, 显然这与测试用例有关系!!!

//CH2902_虫食算
#include <iostream>
#include <cstring>
using namespace std;
char s1[30], s2[30], s3[30]; int N;
//val['A']为A对应数字, 未确定时val['A'] < 0, ok的第0位为1表示'A'对应数字已经确定
//used[i]为1表示值i对应字母已经确定, 为0表示未确定 
int val[200], ok, used[30];
//将num填到空格val[ch], 并更新ok, used 
void fill(int ch, int num){
	val[ch] = num, ok ^= 1 << num, used[num] = 1;
}
//如果当前方案成立, 返回true, 不成立返回false 
bool check(){
	for(int i = N, ca = 0; i >= 1; --i){
		int s = val[s1[i]] + val[s2[i]] + ca;
		if(s >= N) s %= N, ca = 1; else ca = 0;
		if(s != val[s3[i]]) return false;
	}
	return true;
}
//now当前正在考察的算式的列(最低位对应第0列), ca第now + 1列的进位值 
void dfs(int now, int ca){
	if(ok == (1 << N) - 1) return;
	int a = s1[now], b = s2[now], c = s3[now];
	//如果a, b, c对应值均已确定
	if(val[a] >= 0 && val[b] >= 0 && val[c] >= 0){
		if(!(val[a] + val[b] + ca == val[c] || val[a] + val[b] + ca == N + val[c])) return;
		dfs(now - 1, (val[a] + val[b] + ca) / N); return;
	} 
	//当前计算结果剪枝, 已知两个加数的值 
	if(val[a] >= 0 && val[b] >= 0){
		int sum = val[a] + val[b] + ca, tca = sum >= N? 1: 0; sum %= N;
		if(used[sum]) return; 
		fill(c, sum), dfs(now - 1, tca); return;
	}
	//已知一个加数与和的值
	if(val[a] >= 0 && val[c] >= 0){
		if(val[c] >= val[a] + ca){
			int tb = val[c] - val[a] - ca; if(used[tb]) return;
			fill(b, tb), dfs(now - 1, 0); return;
		}
		int tb = val[c] + N - val[a] - ca; if(used[tb]) return;
		fill(b, tb), dfs(now - 1, 1); return;
	} 
	if(val[b] >= 0 && val[c] >= 0){
		if(val[c] >= val[b] + ca){
			int ta = val[c] - val[b] - ca; if(used[ta]) return;
			fill(a, ta), dfs(now - 1, 0); return;
		}
		int ta = val[c] + N - val[b] - ca; if(used[ta]) return;
		fill(a, ta), dfs(now - 1, 1); return;
	}
	//至此说明当前第now列至少有两个值尚未确定 
	int arrv[50], tok, arru[30]; 
	memcpy(arrv + 1, val + 'A', sizeof(int) * N), memcpy(arru, used, sizeof(int) * N), tok = ok; 
	//a未确定 
	if(val[a] < 0){
		for(int i = N; i >= 0; --i)
			if(!used[i]){
				fill(a, i), dfs(now, ca);
				if(ok == (1 << N) - 1 && check()) return; 
				else memcpy(val + 'A', arrv + 1, sizeof(int) * N), memcpy(used, arru, sizeof(int) * N), ok = tok; 
			}
		return; 
	}
	if(val[b] < 0){
		for(int i = N; i >= 0; --i)
			if(!used[i]){
				fill(b, i), dfs(now, ca);
				if(ok == (1 << N) - 1 && check()) return; 
				else memcpy(val + 'A', arrv + 1, sizeof(int) * N), memcpy(used, arru, sizeof(int) * N), ok = tok;
			}
		return;	
	}
	if(val[c] < 0)
		for(int i = N; i >= 0; --i)
			if(!used[i]){
				fill(c, i), dfs(now, ca);
				if(ok == (1 << N) - 1 && check()) return; 
				else memcpy(val + 'A', arrv + 1, sizeof(int) * N), memcpy(used, arru, sizeof(int) * N), ok = tok;
			}
} 
int main(){
	cin >> N >> s1 + 1 >> s2 + 1 >> s3 + 1;
	memset(val, 0xff, sizeof(val));
	dfs(N, 0); 
	for(int i = 'A'; i <= 'A' + N - 1; ++i) cout << val[i] << " ";
} 

猜你喜欢

转载自blog.csdn.net/solider98/article/details/84144206