DFS及其优化

DFS及其优化

[优化剪枝]
1.优化搜索顺序 
先搜索节点少的分支,如果搜进来一个大分支而答案不在此分支就会浪费大量时间。 

2.可行性剪枝
如果当前分支不可行就退出剪枝。
 
3.最优性剪枝
如果当前搜索到的答案已经比搜过的答案差了,就退出当前剪枝。
即如果此分支确定不是最优解(差于已有解)就 return。 
 
4.记忆化搜索(=排除等效冗余) 
记录之前搜过 Data ,避免重复搜。 

例题:
1.accoders的【一本通基础搜索与回溯】红与黑1862
思路:一个简单的dfs,但是n和m的输入是反的!!! 
code: 
#include<bits/stdc++.h>
using namespace std;
char a[50][50];
int dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1},vis[50][50];
int n,m,sum=0;
int dfs(int x,int y){
	for(int i=1;i<=4;i++){
		int xx=x+dx[i],yy=y+dy[i];
		if(xx>0&&xx<=m&&yy>0&&yy<=n&&a[xx][yy]=='.'&&!vis[xx][yy]){
			sum++;
			vis[xx][yy]=1;
			dfs(xx,yy);
		}
	}
	return sum;
}
int main(){
	while(1){
		cin>>n>>m;
		if(n==0&&m==0){
			return 0;
		}
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				cin>>a[i][j];
			}
		}
		int sx,sy;
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				if(a[i][j]=='@'){
					sx=i,sy=j;
				}
			}
		}
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				vis[i][j]=0;
			}
		}
		sum=1;
		vis[sx][sy]=1;
		cout<<dfs(sx,sy)<<"\n";
	} 
	return 0;
}
2.
accoders【一本通基础搜索与回溯】马走日1865
思路:
边界是0~n-1和0~m-1!!! 
code:
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,vis[10][10];
int dx[10]={0,2,2,1,-1,-2,-2,1,-1},dy[10]={0,1,-1,2,2,1,-1,-2,-2};
int ans=0,tot;
void dfs(int nx,int ny,int now){
	if(tot==now){
		ans++;
		return;
	}
	for(int i=1;i<=8;i++){
		int xx=nx+dx[i],yy=ny+dy[i];
		if(xx>=0&&xx<n&&yy>=0&&yy<m&&!vis[xx][yy]){
			vis[xx][yy]=1;
			dfs(xx,yy,now+1);
			vis[xx][yy]=0;
		}
	}
}
int main(){
	int T;
	cin>>T;
	while(T--){
		ans=0;
		cin>>n>>m>>x>>y;
	//	memset(vis,0,sizeof(vis));
		tot=n*m;
		vis[x][y]=1;
		ans=0;
		dfs(x,y,1);
		vis[x][y]=0; 
		cout<<ans<<"\n";
	}
	
	return 0;
}
3.
accoders 【算法进阶 搜索深度优先搜索】小猫爬山
luogu P10483 小猫爬山
思路:
从大到小排,能塞就塞,不能就新开。
code:
#include<bits/stdc++.h>
using namespace std;
int a[101],sum[101];
int n,w;
int cmp(int x,int y){
	return x>y;
}
int ans;
void dfs(int u,int k){
	if(k>=ans)return;
	if(u==n){
		ans=k;
		return ;
	}
	for(int i=0;i<k;i++){
		if(sum[i]+a[u]<=w){
			sum[i]+=a[u];
			dfs(u+1,k);
			sum[i]-=a[u];
		}
	}
	sum[k]=a[u];
	dfs(u+1,k+1); 
	sum[k]=0; 
}
int main(){
	cin>>n>>w;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n,cmp);
	ans=n;
	dfs(0,0);
	cout<<ans;
	return 0;
}
4.
luogu P1784 数独
思路:
一个判断行,列,小方格内有没有重复数字的dfs 
code:
#include<bits/stdc++.h>
using namespace std;
int h[11][11],l[11][11],g[11][11],sd[11][11];
void go_out(){
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			cout<<sd[i][j]<<" ";
		}
		cout<<"\n";
	}
	exit(0);
}
void dfs(int x,int y){
	if(sd[x][y]!=0){
		if(x==9&&y==9){
			go_out();
		}else if(y==9){
			dfs(x+1,1);
		}else{
			dfs(x,y+1);
		}
	}else{
		for(int i=1;i<=9;i++){
			if(!h[x][i]&&!l[y][i]&&!g[(x-1)/3*3+(y-1)/3+1][i]){
				sd[x][y]=i;
				h[x][i]=l[y][i]=g[(x-1)/3*3+(y-1)/3+1][i]=1;
				if(x==9&&y==9){
					go_out();
				}else if(y==9){
					dfs(x+1,1);
				}else{
					dfs(x,y+1);
				}
				h[x][i]=l[y][i]=g[(x-1)/3*3+(y-1)/3+1][i]=0;
				sd[x][y]=0;
			}
		}
	}
}
int main(){
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			int t;
			cin>>t;
			if(t!=0){
				h[i][t]=l[j][t]=g[(i-1)/3*3+(j-1)/3+1][t]=1;
			}
			sd[i][j]=t;
		}
	}
	dfs(1,1);
	return 0;
}
posted @ 2025-01-17 07:58  lbh123  阅读(59)  评论(0)    收藏  举报