DFS【搜索1】
DFS模板
void dfs(int depth)//depth表示當前的層數(或深度) { if(depth>n)//到達葉子節點,該路已走到盡頭 return; for(int i=1;i<=n;i++)//n表示最大的值,即最大深度為n { if(b[i]==0)//b數組表示探索的狀態,1表示已被探索,0表示尚未被探索 { b[i]=1;//標記當前的b[i]已被探索 a[level]=i;//記錄當前的節點值 dfs(level+1);//進一步的搜索 b[i]=0;//還原當前的b[i]元素被探索的狀態 } } }
數字型搜索
全排列問題
題目描述
排列與組合是常用的數學方法。
先給一個正整數 ( 1 < = n < = 10 )
例如n=3,所有組合,並且按字典序輸出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
輸入
輸入一個整數n( 1<=n<=10)
輸出
輸出所有全排列
每個全排列一行,相鄰兩個數用空格隔開(最後一個數後面沒有空格)
樣例輸入 Copy
3
樣例輸出 Copy
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
#include<bits/stdc++.h> #include<queue> using namespace std; const int N=100; typedef long long ll; int n,a[10010],b[10010]; void print() { for(int i=1;i<=n;i++) { printf("%5d",a[i]); } cout<<endl; } void dfs(int level) { if(level==n+1) { print(); return; } for(int i=1;i<=n;i++) { if(b[i]==0) { b[i]=1; a[level]=i; dfs(level+1); b[i]=0; } } } int main() { cin>>n; dfs(1); }
【牛客】 Factorial
1、暴力解題,程式碼略;
2、dfs解題(重點),萬物皆可搜,有點類似斐波那契遞歸
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll maxn=1e5+10; #define IO ios::sync_with_stdio(false), cin.tie(0) #define T int t ;cin >> t;while(t--) ll a[maxn]; ll dfs(ll n) { if(n<=1) { return 1; } else { return dfs(n-1)*n; } } int main() { T { ll n; scanf("%lld",&n); printf("%lld\n",dfs(n)); } }
地圖型搜索
n皇后問題
#include<bits/stdc++.h> using namespace std; typedef long long ll; int n,y[100010],s,ans[100010]; bool check(int x)//剪枝,判斷兩點的位置\\ 兩點的斜率的絕對值不得等於1;兩點不得在同一水平線上(包括同一行和同一列) { for(int i=1;i<x;i++)//i本身就是指行號,y[i]表示對應的列號 { if(abs(x-i)==abs(y[x]-y[i])||y[x]==y[i]||x==i) { return 0; } } return 1; } void dfs(int num) { if(num>n)//越界處理 { s++; return; } for(int i=1;i<=n;i++) { y[num]=i;//將當前的行號賦值給第num個皇后 if(check(num)) dfs(num+1);//進行下一步的搜索 } } int main() { for(int i=1;i<=10;i++) { n=i; s=0; dfs(1); ans[i]=s; } while(~scanf("%d",&n)&&n) printf("%d\n",ans[n]); }
POJ3083 Children of the Candy Corn
左搜索(Ldfs)+右搜索(Rdfs)+最短路徑搜索(bfs)
搜索方位
左搜索:
始終靠左搜索,如果左邊是牆#,那就往上面搜索;上面是牆#,那就往右邊搜索;右邊是牆#則返回之前的位置,即往後搜索。
右搜索:
bfs最短路搜索:
創建隊列,在一個點的周圍的同一層搜索(這是與DFS的區別最大之處),用vis數組標記是否被搜索過
#include<bits/stdc++.h> typedef long long ll; using namespace std; const int N=55; char mp[41][41]; int vis[41][41]; int m,n,f,ans1,ans2; int head_x,head_y,tail_x,tail_y; int dir1[4][2]= {-1,0,1,0,0,1,0,-1}; struct node { int x,y,step; } head,tail; bool judge(int xx,int yy) { if(xx>=1&&xx<=m&&yy>=1&&yy<=n&&mp[xx][yy]!='#'&&vis[xx][yy]==0) return true; return false; } void dfs1(int xx,int yy,int step,int dir)//逆時針走法 { if(f==1) return; if(xx==tail_x&&yy==tail_y) { f=1; ans1=step; return; } if(dir==1)//右上左下 { if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4); if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1); if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2); if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3); } else if(dir==2)//上左下右 { if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1); if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2); if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3); if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4); } else if(dir==3)//左下右上 { if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2); if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3); if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4); if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1); } else//右下上左 { if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3); if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4); if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1); if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2); } } void dfs2(int xx,int yy,int step,int dir) { if(f==1) { return; } if(xx==tail_x&&yy==tail_y) { f=1; ans2=step; return; } if(dir==1) { if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2); if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1); if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4); if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3); } else if(dir==2) { if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3); if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2); if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1); if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4); } else if(dir==3) { if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4); if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3); if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2); if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1); } else { if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1); if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4); if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3); if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2); } } int bfs() { queue<node> q; while(!q.empty()) { q.pop(); } head.x=head_x,head.y=head_y,head.step=1; q.push(head); vis[head_x][head_y]=1; while(!q.empty()) { head=q.front(); q.pop(); if(head.x==tail_x&&head.y==tail_y) { return head.step; } for(int i=0; i<4; i++) { tail.x=head.x+dir1[i][0]; tail.y=head.y+dir1[i][1]; if(judge(tail.x,tail.y)) { tail.step=head.step+1; vis[tail.x][tail.y]=1; q.push(tail); } } } return 0; } int main() { int T; scanf("%d",&T); while(T--) { memset(vis,0,sizeof vis); scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { for(int j=1; j<=n; j++) { scanf(" %c",&mp[i][j]); if(mp[i][j]=='S') { head_x=i; head_y=j; } if(mp[i][j]=='E') { tail_x=i; tail_y=j; } } } f=0; ans1=0; dfs1(head_x,head_y,1,1); f=0; ans2=0; dfs2(head_x,head_y,1,1); int ans3=bfs(); printf("%d %d %d\n",ans1,ans2,ans3); } }
棋盤問題
n表示棋盤的大小是n*n,m表示棋子的數量,結束dfs的條件就是當前的棋子數量大於等於m(因為初始的0就已經存在1顆棋子了)。
#include<iostream> #include<algorithm> #include<string> #include<string.h> #define IO ios::sync_with_stdio(false), cin.tie(0) typedef long long ll; using namespace std; const ll maxn=1e5+10; char mp[100][100]; bool vis[100]; ll n,m,s; void dfs(ll x,ll y) { if(y>=m) { s++; return; } for(ll i=x; i<n; i++) for(ll j=0; j<n; j++) { if(vis[j]==false&&mp[i][j]=='#') { vis[j]=true; dfs(i+1,y+1); vis[j]=false; } } } int main() { while(1) { scanf("%lld%lld",&n,&m); if(n==-1&&m==-1) break; memset(vis,0,sizeof vis); memset(mp,0,sizeof mp); for(ll i=0; i<n; i++)scanf("%s",mp[i]); s=0; dfs(0,0); cout<<s<<endl; } }
Oil Deposit
#include <bits/stdc++.h> using namespace std ; typedef long long ll; ll m,n; char mp[110][110]; ll dir[8][2]= { {0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1} };//方向可以任意,當前方向見圖 void dfs(ll x,ll y) { mp[x][y]='*';//把當前的@轉換成*,避免重複查找 for(ll i=0; i<8; i++) { ll xx=x+dir[i][0],yy=y+dir[i][1]; if(xx>=1&&xx<=m&&yy>=1&&yy<=n&&mp[xx][yy]=='@') { dfs(xx,yy); } } return;//遞歸結束 } int main() { while(~scanf("%lld%lld",&m,&n)&&n&&m) { ll sum=0; for(ll i=1; i<=m; i++) { for(ll j=1;j<=n;j++) { cin>>mp[i][j]; //scanf(" %c",&mp[i][j]); //兩種讀入方式均可,要注意的是,用scanf()讀入的話,需要在%c之前加入一個空格,這是專門用來吸收"\n" } } for(ll i=1; i<=m; i++) { for(ll j=1; j<=n; j++) { if(mp[i][j]=='@') { dfs(i,j); sum++; } } } cout<<sum<<endl; } }
Red and Black
用dfs搜索最長路,黑磚可走,紅磚不可走,@表示出發點,輸出最大黑磚數
#include<iostream> #include<string> #include<cstdio> using namespace std; typedef long long ll; ll m,n; char mp[25][25]; ll dir[4][2]={ {-1,0},{1,0},{0,-1},{0,1} }; ll s; void dfs(ll x,ll y) { ll xx,yy; for(ll i=0;i<4;i++) { xx=x+dir[i][0]; yy=y+dir[i][1]; if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&mp[xx][yy]!='#') { s++; mp[xx][yy]='#'; dfs(xx,yy); } } } int main() { while(~scanf("%lld %lld",&m,&n)&&m&&n) { ll xx,yy; for(ll i=1;i<=n;i++) { for(ll j=1;j<=m;j++) { scanf(" %c",&mp[i][j]); if(mp[i][j]=='@') { xx=i; yy=j; } } } s=1; mp[xx][yy]='#'; dfs(xx,yy); cout<<s<<endl; } }
P1162 填塗顏色
建議從1開始讀入,因為這樣有一個好處,能夠建立起天然的下標為0的圍牆數組,可以防止數組下標小於0,以至於越界
dfs1
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll maxn=1e6+10; ll n; ll mp[35][35]; ll vis[35][35]; ll dir[4][2]= { {-1,0},{1,0},{0,-1},{0,1} }; void dfs(ll x,ll y) { if(x==0||y==0||x>n||y>n) return; for(ll i=0; i<4; i++) { ll xx=x+dir[i][0],yy=y+dir[i][1]; if(mp[xx][yy]!=1&&xx>=1&&xx<=n&&yy>=1&&yy<=n&&!vis[xx][yy]) { vis[xx][yy]=1; dfs(xx,yy); } } } int main() { memset(vis,0,sizeof vis); memset(mp,0,sizeof mp); scanf("%lld",&n); for(ll i=1; i<=n; i++) { for(ll j=1; j<=n; j++) { cin>>mp[i][j]; } } for(ll i=1;i<=n;i++) { if(mp[1][i]==0) dfs(1,i); if(mp[i][1]==0) dfs(i,1); if(mp[n][i]==0) dfs(n,i); if(mp[i][n]==0) dfs(i,n); } for(ll i=1; i<=n; i++) { for(ll j=1; j<=n; j++) { if(j>1) cout<<' '; if(mp[i][j]!=1&&!vis[i][j]) mp[i][j]=2; cout<<mp[i][j]; } cout<<endl; } }
dfs2
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll mp[35][35]; ll n; ll dir[4][2]={ {-1,0},{1,0},{0,-1},{0,1} }; void dfs(ll x,ll y) { mp[x][y]=3; for(ll i=0;i<4;i++) { ll xx=x+dir[i][0],yy=y+dir[i][1]; if(xx>=0&&yy>=0&&xx<=n+1&&yy<=n+1&&mp[xx][yy]==0) { dfs(xx,yy); } } } int main() { scanf("%lld",&n); for(ll i=1;i<=n;i++) { for(ll j=1;j<=n;j++) { cin>>mp[i][j]; } } dfs(0,0); for(ll i=1;i<=n;i++) { for(ll j=1;j<=n;j++) { if(j>1) { cout<<' '; } if(mp[i][j]==3) { mp[i][j]=0; } else if(mp[i][j]==0) { mp[i][j]=2; } cout<<mp[i][j]; } cout<<endl; } }
————————————————————————————————————-