DFS【洛谷P1092】
阿新 • • 發佈:2018-11-10
獻上題目連結:https://www.luogu.org/problemnew/show/P1092
又碰到了這種帶有模擬思路的DFS,在以前的印象裡,DFS都是與圖論搜尋掛上鉤的。原來DFS的應用這麼廣泛,在洛谷上刷了幾個DFS,也算對於這種演算法有了新的認識吧。
拿到題目,我想直接全排列搞一波試一試,受限於教室裡面的環境以及自己的模擬能力,我也就只是想了想。寫了一半發現寫不出來。(我怎麼可以這麼蒻)
不廢話了,直接說思路:
這個題目是一個思路很清晰的DFS,因為是加法豎式,而且我也沒有reverse,所以直接從第1行第n列開始DFS,(第一行第n列就是豎式的左上角的那個字母,大家應該能想明白)。如果沒找到第3行,就在該列繼續往下找,找到了第3行,就重新找第1行第x-1列。(方向是從上到下,從右往左)
因為算式的三行長度相等,所以判斷成不成立的條件就是第1列的進位是0。
這樣就可以很顯然的寫出程式碼了,但是可能會TLE。
我們在判斷等式是否成立時,每一步都是可以判斷的,如果有一步不成立就可以直接return掉了。這樣可能大概應該會剪掉不少枝。
空口無憑,上程式碼!
#include <bits/stdc++.h> using namespace std; const int maxn = 30; int n; string str[5]; int num[maxn]; bool vis[maxn]; int getid(char ch) { return ch-'A'+1; } void init() { memset(num,-1,sizeof(num)); memset(vis,0,sizeof(vis)); } void dfs(int x,int y,int t) { if(x==0 && t==0) { for(int i=1;i<=n;i++) { cout<<num[i]; if(i<n) { cout<<" "; } } cout<<endl; return; } for(int i=x-1;i>=1;i--) { int w1 = num[getid(str[1][i])]; int w2 = num[getid(str[2][i])]; int w3 = num[getid(str[3][i])]; if(w1==-1 || w2==-1 || w3==-1) { continue; } if((w1+w2)%n!=w3 && (w1+w2+1)%n!=w3) { return; } } if(num[getid(str[y][x])] == -1) { for(int i=n-1;i>=0;i--) { if(!vis[i]) { if(y!=3) { num[getid(str[y][x])] = i; vis[i] = 1; dfs(x,y+1,t); num[getid(str[y][x])] = -1; vis[i] = 0; } else { int w = num[getid(str[1][x])] + num[getid(str[2][x])] + t; if(w%n != i) { continue; } num[getid(str[y][x])] = i; vis[i] = 1; dfs(x-1,1,w/n); num[getid(str[y][x])] = -1; vis[i] = 0; } } } } else { if(y!=3) { dfs(x,y+1,t); } else { int w = num[getid(str[1][x])] + num[getid(str[2][x])] + t; if(w%n != num[getid(str[3][x])]) { return; } dfs(x-1,1,w/n); } } } int main() { while(cin>>n) { init(); for(int i=1;i<=3;i++) { cin>>str[i]; str[i].insert(0,"#"); } dfs(n,1,0); } return 0; }
PS:真的好蒻,DFS原來有這麼多玩法。