本文章主要记录第七周做题的思路。如有错误,请大佬斧正。若大佬有更好的思路,也请指教。
本周涉及DFS深度优先搜索。
一、B3625 迷宫寻路
思路:
跟第六周的电梯很像,用BFS可以轻松搞定。
代码:
#include <bits/stdc++.h>
using namespace std;
struct pos{
int xx,yy;
char vv;
};
pos f[102][102],cur,nex;
int a[4]={0,0,1,-1},
b[4]={1,-1,0,0};
int n,m,no=0;
queue<pos> qu;
int main()
{
cin>>n>>m;
for(int x=0;x<=n+1;x++)
{
for(int y=0;y<=m+1;y++)
f[x][y].vv='#';
}
for(int x=1;x<=n;x++)
{
for(int y=1;y<=m;y++)
{
cin>>f[x][y].vv;
f[x][y].xx=x;
f[x][y].yy=y;
}
}
qu.push(f[1][1]);
while(!qu.empty())
{
cur.vv=qu.front().vv;
cur.xx=qu.front().xx;
cur.yy=qu.front().yy;
qu.pop();
//到达
if(cur.xx==n&&cur.yy==m)
{
cout<<"Yes";
return 0;
}
for(int i=0;i<4;i++)
{
//四处找路
if(f[cur.xx+a[i]][cur.yy+b[i]].vv=='.')
{
//继续走
f[cur.xx+a[i]][cur.yy+b[i]].vv='#';
qu.push(f[cur.xx+a[i]][cur.yy+b[i]]);
}
}
}
cout<<"No";
}
二、P1706 全排列问题
思路:
本题用DFS,会一条路走到黑(如图1),而BFS会一层一层地搜索(如图2)
图1:
图2:
值得注意的是,DFS的回溯确实是一个难点。return返回的是调用这个函数的位置。举个例子:假设dfs(4)要return,那它会回到dfs(3),而dfs(3)又是dfs(2)调用的,所以又会回到dfs(2),然后回到dfs(1).这是正常情况。但下面代码有点特殊,就是for循环会打断dfs的回溯。
代码:
#include <bits/stdc++.h>
using namespace std;
int step,n,num[10]={0},vis[10]={0};
void dfs(int step)
{
if(step==n+1)// 如果达到目标状态,输出结果并返回
{
for(int i=1;i<=n;i++)
{
cout<<setw(5)<<num[i];
}
cout<<endl;
return;//回溯,回到调用的位置(若上个位置也是被调用的,则会一直在嵌套中一直返回上一级,直到被for打断)
}
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
vis[i]=1;
num[step]=i;
dfs(step+1);// 继续向下一个状态进行搜索
vis[i]=0;// 回溯,将当前元素的访问状态恢复
}
}
}
int main()
{
cin>>n;
dfs(1);
}
三、P1451 求细胞数量
思路:
BFS的搜索,没啥说的。
代码:
#include <bits/stdc++.h>
using namespace std;
struct pos{
int xx,yy;
char vv;
};
pos f[102][102],cur;
int a[4]={0,0,1,-1},
b[4]={1,-1,0,0};
int n,m,no=0;
queue<pos> qu;
void bfs(int x,int y)
{
if(f[x][y].vv=='0')
{
return;
}
qu.push(f[x][y]);
while(!qu.empty())
{
f[x][y].vv=='0';
cur=qu.front();
qu.pop();
for(int i=0;i<4;i++)
{
//四处找
if(f[cur.xx+a[i]][cur.yy+b[i]].vv!='0')
{
//找到
f[cur.xx+a[i]][cur.yy+b[i]].vv='0';
qu.push(f[cur.xx+a[i]][cur.yy+b[i]]);
}
}
}
no++;
return;
}
int main()
{
cin>>n>>m;
for(int x=0;x<=n+1;x++)
{
for(int y=0;y<=m+1;y++)
f[x][y].vv='0';
}
for(int x=1;x<=n;x++)
{
for(int y=1;y<=m;y++)
{
cin>>f[x][y].vv;
f[x][y].xx=x;
f[x][y].yy=y;
}
}
for(int x=1;x<=n;x++)
{
for(int y=1;y<=m;y++)
{
bfs(x,y);
}
}
cout<<no;
}
四、P1219 [USACO1.5] 八皇后 Checker Challenge
思路:
DFS的框架与第二题是一样的。
但关于两个皇后是否同行、同列、同对角线的判断还是很有意思的,尤其是是否在同一对角线的判断(当然主要是我见识太少了)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,x,no=0,tem[105];
bool sh[105],xi[105],fxi[105];//判断同行、列、对角线
void dfs(int x)
{
//判断满足条件
if(x>n)
{
no++;//计数
if(no<=3)
{
for(int xx=1;xx<=n;xx++)
{
cout<<tem[xx]<<" ";
}
cout<<endl;
}
return;
}
//循环列数,找地放皇后
for(int i=1;i<=n;i++)
{
if(!sh[i]&&!xi[x-i+n]&&!fxi[x+i])
{
tem[x]=i;
sh[i]=1;//标记
xi[x-i+n]=1;
fxi[x+i]=1;
//找到后,行数+1
dfs(x+1);
//回溯,将bool还原
sh[i]=0;
xi[x-i+n]=0;
fxi[x+i]=0;
}
}
}
int main()
{
cin>>n;
dfs(1);
cout<<no;
}