【搜索】\(P1092\)蟲食算
首先,我們只考慮加法的蟲食算。這裏的加法是N進制加法,算式中三個數都有N位,允許有前導的0。
其次,蟲子把所有的數都啃光了,我們只知道哪些數字是相同的,我們將相同的數字用相同的字母表示,不同的數字用不同的字母表示。如果這個算式是N進制的,我們就取英文字母表午的前N個大寫字母來表示這個算式中的0到N-1這N個不同的數字:但是這N個字母並不一定順序地代表0到N-1。輸入數據保證N個字母分別至少出現一次。輸入數據保證有且僅有一組解。
輸入格式
包含四行。
第一行有一個正整數\(N(N \leq 26)\)。
後面的三行,每行有一個由大寫字母組成的字符串,分別代表兩個加數以及和。這3個字符串左右兩端都沒有空格,從高位到低位,並且恰好有N位。
輸出格式
一行,即唯一的那組解。
解是這樣表示的:輸出N個數字,分別表示A,B,C,…所代表的數字,相鄰的兩個數字用一個空格隔開,不能有多餘的空格。
對於30%的數據,保證有\(N \leq 10\);
對於50%的數據,保證有\(N \leq 15\);
對於全部的數據,保證有\(N \leq 26\)。
Solution
搜索是比較好想的。但若直接枚舉全排列需要n!,那麼需要剪枝。
考慮加法,進位的話只會進1,所以如果(A + B) % n != C && (A + B +1) % n != C,顯然不合法。然後因爲三個數都是N位,所以最高位不可能進位。
那麼什麼搜索順序會更優呢?從右往左,也就是從低位到高位。從右往左,按照字母出現順序搜索,能在很大程度上提高剪枝效率。
最後,最關鍵的一點,是一個exit(0)的應用。第一次知道這到底是個什麼。
exit(0):正常運行程序並退出程序。 exit 是一個函數。 exit是系統調用級別的,它表示了一個進程的結束。 exit是進程的退出。 exit是操作系統提供的(或者函數庫中給出的)。 exit函數是退出應用程序,刪除進程使用的內存空間,並將應用程序的一個狀態返回給OS,這個狀態標識了應用程序的一些運行信息,這個信息和機器和操作系統有關,一般是 0 爲正常退出,非0 爲非正常退出。 6. 非主函數中調用return和exit效果很明顯,但是在main函數中調用return和exit的現象就很模糊,多數情況下現象都是一致的。
#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
long long read(){
long long x = 0; int f = 0; char c = getchar();
while(c < '0' || c > '9') f |= c == '-', c = getchar();
while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return f? -x:x;
}
int a[30], b[30], c[30], num[30], qu[30], n, cnt;
char s1[30], s2[30], s3[30];
bool used[30];
bool ok(){//最後判斷一下是否滿足等式
for(int i = n - 1, x = 0; i >= 0; --i){
int A = num[a[i]], B = num[b[i]], C = num[c[i]];
if((A + B + x) % n != C) return 0;
x = (A + B + x) / n;
}
return 1;
}
void print(){//輸出
printf("%d", num[0]);
for(int i = 1; i < n; ++i) printf(" %d", num[i]);
exit(0);//減少遞歸返回時間
}
void dfs(int x){
if(num[a[0]] + num[b[0]] >= n) return;//最高位沒有進位
for(int i = n - 1; i >= 0; --i){
int A = num[a[i]], B = num[b[i]], C = num[c[i]];
if(A == -1 || B == -1 || C == -1) continue;
if((A + B) % n != C && (A + B + 1) % n != C) return;//判每一位是否合法
}
if(x == n){
if(ok()) print();
return;
}
for(int i = n - 1; i >= 0; --i)
if(!used[i]){
num[qu[x]] = i, used[i] = 1;
dfs(x + 1);
num[qu[x]] = -1, used[i] = 0;//回溯
}
}
void Sort(int x){//預處理遞歸枚舉順序
if(!used[x]) used[x] = 1, qu[cnt++] = x;
}
int main(){
freopen("1.txt", "r", stdin);
freopen("1.out", "w", stdout);
n = read();
scanf("%s%s%s", s1, s2, s3);
for(int i = 0; i < n; ++i)
a[i] = s1[i] - 'A', b[i] = s2[i] - 'A', c[i] = s3[i] - 'A', num[i] = -1;
for(int i = n - 1; i >= 0; --i){
Sort(a[i]);//預處理順序
Sort(b[i]);
Sort(c[i]);
}
for(int i = 0; i < n; ++i) used[i] = 0;
dfs(0);
return 0;
}