dfs 学习笔记
DFS算法是一一个递归算法,需要借助一个递归工作栈,故它的空问复杂度为O(V)。
遍历图的过程实质上是对每个顶点查找其邻接点的过程,其耗费的时间取决于所采用结构。
邻接表表示时,查找所有顶点的邻接点所需时间为O(E),访问顶点的邻接点所花时间为O(V),此时,总的时间复杂度为O(V+E)。
邻接矩阵表示时,查找每个顶点的邻接点所需时间为O(V),要查找整个矩阵,故总的时间度为O(V^2)。
v为图的顶点数,E为边数。
1.搜索的数据结构基础 STL###
a. 栈 stack
Last in First out
stack<int> s; //定义方法
//基本操作
s.push(x) //压栈
s.pop(); //突出栈顶元素
s.top(); //查询栈顶元素
b. 队列 Queue
First in First out
Queue<int> Q; //定义队列
//基本操作
Q.push(x); // 进队
Q.pop(); // 出队
Q.front(); //查询队首元素
Q.back(); //查询队尾元素
Q.empty(); //查询队列是否为空
Q.size(); //查询对内元素数量
2.深度优先搜索dfs 例题###
全排列
用搜索找到全排列
#include<cstdio>
#include<iostream>
using namespace std;
int a[20];
int n;
void dfs(int x);
bool vis[20];
int main(){
cin>>n;
dfs(1);
return 0;
}
void dfs(int x){
if(x==n+1){
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(!vis[i]){
a[x]=i;
vis[i]=1;
dfs(x+1);
vis[i]=0;
}
}
}
选数游戏 luogu P1036
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int n,k,Ans;
int p[30];
bool CheckPri(int n){
if(n==1||n==0) return false;
if(n==2) return true;
for(int i=2;i*i<=n;i++)
if(n%i==0) return false;
return true;
}
void dfs(int res,int pos,int sum){
if(!res){
Ans+=CheckPri(sum);
return;
}
if(pos>n)return;
dfs(res-1,pos+1,sum+p[pos]);
dfs(res,pos+1,sum);
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>p[i];
dfs(k,1,0);
cout<<Ans<<endl;
return 0;
}
一个更简单的选数例题 选自‘挑战程序设计竞赛’例题
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int n,k;
int a[20];
int Ans[20];
bool vis[20];
bool dfs(int x,int sum){
if(x>n)return sum==k;
if(dfs(x+1,sum))return true;
if(dfs(x+1,sum+a[x]))return true;
return false;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
if(dfs(0,0)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
Lake counting 最经典的搜索例题
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int x,y;
char a[110][110];
int Ans;
void dfs(int n,int m){
if(n<1||n>x)return;
if(m<1||m>y)return;
a[n][m]='.';
for(int mx=-1;mx<=1;mx++){
for(int my=-1;my<=1;my++){
if(a[n+mx][m+my]=='W'&&(n+mx)>=1&&(n+mx)<=x&&(m+my)>=1&&(m+my)<=y)
dfs(n+mx,m+my);
}
}
}
int main(){
cin>>x>>y;
for(int i=1;i<=x;i++)
for(int j=1;j<=y;j++)
cin>>a[i][j];
for(int i=1;i<=x;i++){
for(int j=1;j<=y;j++){
if(a[i][j]=='W'){
Ans++;
dfs(i,j);
}
}
}
cout<<Ans<<endl;
return 0;
}
HDUOJ p1010 temper of bone
Dfs 奇偶性剪枝搜索
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int N,M,T;
bool flag=0;
char a[10][10];
bool vis[10][10];
int sx,sy,fx,fy;
int ux[5]={0,0,1,-1};
int uy[5]={1,-1,0,0};
void dfs(int x,int y,int k){
printf("i=%d j=%d\n",x,y);
if(flag)return;
if(k<0) return;
if(x<1||x>N)return;
if(y<1||y>M)return;
if(x==fx&&y==fy&&k==0){
flag=1;
return;
}
int dis=abs(x-fx)+abs(y-fy);
if(k-dis<0)return;
if((k-dis)%2) return;
for(int i=0;i<4;i++){
int px=x+ux[i],py=y+uy[i];
if(a[px][py]!='X'&&!vis[px][py]){
vis[px][py]=1;
dfs(px,py,k-1);
vis[px][py]=0;
}
}
}
int main(){
while(1){
cin>>N>>M>>T;
if(N==0&&M==0&&T==0)break;
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
flag=0;
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++){
cin>>a[i][j];
if(a[i][j]=='S') sx=i,sy=j;
if(a[i][j]=='D') fx=i,fy=j;
}
vis[sx][sy]=1;
dfs(sx,sy,T);
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
Luogu P1135 奇怪的电梯
暴力dfs但是需要避免死循环所以用vis数组标记
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int N,A,B,Ans=2147483647;
bool flag;
bool vis[210];
int K[210];
void dfs(int x,int tim){
if(tim>Ans)return;
if(x>N||x<1)return;
if(x==B){
flag=1;
Ans=min(tim,Ans);
return;
}
if(K[x]==0)return;
if(x+K[x]<=N&&!vis[x+K[x]]){
vis[x+K[x]]=1;
dfs(x+K[x],tim+1);
vis[x+K[x]]=0;
}
if(x-K[x]>=1&&!vis[x-K[x]]){
vis[x-K[x]]=1;
dfs(x-K[x],tim+1);
vis[x-K[x]]=0;
}
}
int main(){
cin>>N>>A>>B;
for(int i=1;i<=N;i++)cin>>K[i];
dfs(A,0);
if(flag)cout<<Ans<<endl;
else cout<<-1<<endl;
return 0;
}
Luogu P 1118 数字三角形
模拟出规律+dfs暴力
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int n,sum;
int c[110][110],Ans[110];
bool vis[110];
void dfs(int num,int tot){
if(tot>sum)return;
if(num>n){
if(tot==sum){
for(int i=1;i<=n;i++)cout<<Ans[i]<<" ";
exit(0); //exit(0)表示结束当前函数进程,回归主函数
}
}
for(int i=1;i<=n;i++){
if(!vis[i]){
vis[i]=1;
Ans[num]=i;
dfs(num+1,tot+i*c[n][num]);
vis[i]=0;
}
}
}
int main(){
cin>>n>>sum;
c[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
c[i][j]=c[i-1][j]+c[i-1][j-1];
//law:用杨辉三角打出一个字表,字典序最小的需要满足sum{i*C[n][i]}
dfs(1,0);
return 0;
}
Luogu p1123 取数游戏
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int T,N,M;
int a[10][10];
int u[]={0,0,0,1,1,-1,-1,1,1},
v[]={0,1,-1,0,0,1,-1,1,-1};
int Ans=-1;
int num[10][10];
int dfs(int x,int y,int sum){
if(y>M){
x++;
y=1;
}
if(x>N){
Ans=max(Ans,sum);
return Ans;
}
if(num[x][y]==0){
for(int i=1;i<9;i++) num[x+u[i]][y+v[i]]++;
dfs(x,y+2,sum+a[x][y]);
for(int i=1;i<9;i++) num[x+u[i]][y+v[i]]--;
}
dfs(x,y+1,sum);
}
int main(){
cin>>T;
while(T--){
cin>>N>>M;
memset(a,0,sizeof(a));
memset(num,0,sizeof(num));
Ans=-1;
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
cin>>a[i][j];
dfs(1,1,0);
cout<<Ans<<endl;
}
return 0;
}