1. 程式人生 > >搜尋_DFS_CH2902_蟲食算

搜尋_DFS_CH2902_蟲食算

點此開啟題目頁面

思路分析:

    從相加的最低兩位開始考察, 注意利用已知兩個數可求第三個數進行剪枝. 注意在下面的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] << " ";
}