目录
DFS
一、基本思想
- 为了求得问题的解,先选择某一种可能情况向前探索;
- 在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索;
- 如此反复进行,直至得到解或证明无解。
模板:迷宫问题
void dfs(int i,int j) //需要变化的量
{
if(满足终止条件时,一般为到达边界问题)
{
需要记录的数值(例如有几条路线或者最多能走多少步)
return;
}
for(需要怎样变化,如果是向四个方向搜,那就是以循环四个方向,根据情况而定)
{
if(不满足条件)
跳过
else
{
标记;
向下搜;
回溯;
}
}
}
代码块:
void dfs(int i,int j)
{
if(i==fx&&j==fy) //搜索到终点位置,结束搜索
{
ans++;
return ;
}
for(int k=0;k<4;k++) //朝着四个方向搜
{
int ii=i+dx[k];
int jj=j+dy[k];
if(ii<1||ii>n||jj<1||jj>m||a[ii][jj]==1||vis[ii][jj]==1) 不满足条件的跳过
{
continue;
}
vis[ii][jj]=1;
dfs(ii,jj);
vis[ii][jj]=0; //回溯
}
}
代码:
#include<bits/stdc++.h>
using namespace std;
int a[1000][1000];
int fx,fy,n,m,t;
int ans;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int vis[1000][1000];
void dfs(int i,int j)
{
if(i==fx&&j==fy)
{
ans++;
return ;
}
for(int k=0;k<4;k++)
{
int ii=i+dx[k];
int jj=j+dy[k];
if(ii<1||ii>n||jj<1||jj>m||a[ii][jj]==1||vis[ii][jj]==1)
{
continue;
}
vis[ii][jj]=1;
dfs(ii,jj);
vis[ii][jj]=0;
}
}
int main()
{
cin>>n>>m>>t;
int sx,sy;
cin>>sx>>sy>>fx>>fy;
int x,y;
for(int i=1;i<=t;i++)
{
cin>>x>>y;
a[x][y]=1;
}
vis[sx][sy]=1;//对起点进行标记
dfs(sx,sy);
cout<<ans<<endl;
return 0;
}
代码:
#include<bits/stdc++.h>
using namespace std;
int a[20];
int ans;
int cab[30];//当前缆车上的重量
int n,w;
bool cmp(int a,int b)
{
return a>b;
}
void dfs(int now,int cnt)//当前是第几只猫,缆车的数量
{
if(cnt>=ans)
return ;
if(now==n+1)
{
ans=min(ans,cnt);
return ;
}
for(int i=1;i<=cnt;i++)
{
if(cab[i]+a[now]<=w) //当前缆车上的重量没有超过w
{
cab[i]+=a[now];
dfs(now+1,cnt); //猫的数量增加,缆车数量不变
cab[i]-=a[now]; //回溯
}
}
//如果超过,新开一辆缆车
cab[cnt+1]=a[now];
dfs(now+1,cnt+1); //猫的数量增加,缆车数量增加
cab[cnt+1]=0; //回溯
}
int main()
{
cin>>n>>w;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+n+1,cmp);
ans=n;
dfs(1,0);
cout<<ans<<endl;
return 0;
}
BFS
BFS之所以称之为广度优先搜索,因为它的拓展方式是层层拓展,这保证了第一次搜索到一个点时,从起点到这个点的步数一定时最小的。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y;
int p[500][500]; //步数
int vis[500][500]; //标记是否走过
int dx[8]={1,1,2,2,-1,-1,-2,-2}; //马走有八个方向
int dy[8]={2,-2,1,-1,2,-2,1,-1};
struct st
{
int a,b; //坐标
};
void bfs(int a,int b)
{
memset(p,-1,sizeof(p));
vis[a][b]=1; //标记起点
p[a][b]=0; //起点步数为0
queue<st>q; //设队列
st t;
t.a=a;
t.b=b;
q.push(t);
while(!q.empty())
{
st tt;
tt=q.front();
q.pop();
for(int i=0;i<8;i++) //八个方向遍历
{
int xx=tt.a+dx[i];
int yy=tt.b+dy[i];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&!vis[xx][yy]) //不超出边界并且没有标记过
{
vis[xx][yy]=1; //进行标记
st ttt;
ttt.a=xx;
ttt.b=yy;
p[xx][yy]=p[tt.a][tt.b]+1;
q.push(ttt);
}
}
}
}
int main()
{
cin>>n>>m>>x>>y;
bfs(x,y);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
printf("%-5d",p[i][j]);
printf("\n");
}
}