*(寒假训练第一天)
今日DFS搜索问题如下:
1. P1162 填涂颜色
2. P1605 迷宫
3. P1036 [NOIP2002 普及组] 选数
4. P2392 kkksc03考前临时抱佛脚
(一) 收获最大的还是填涂颜色问题:
题目中数字矩阵有0和1两种数字,要求将1包围的数字0全部变 为2并输出变换后的矩阵;
思考:这里可以将 1 包围的 0 和在外围的 0 ,通过深度优先搜索标记 区分开来,比如将外围的 0 变为3,被包围的 0 不变化即可。
#include<iostream>
using namespace std;
const int N = 1000;
int n,a[N][N];
int x[4] = {-1,1,0,0};//上下左右
int y[4] = {0,0,-1,1};
void dfs(int p,int q){
int i;
//此处条件是不超出矩阵边界,且这个点不是 1 (1相当于迷宫问题的墙壁)
if (p<0 || p>n+1 || q<0 || q>n+1 || a[p][q]!=0) return;
a[p][q] = 3;
for (i=0;i<4;i++) dfs(p+x[i],q+y[i]);//向四个方向搜索
}
int main()
{
cin>>n;
for(int i = 1;i<=n;i++)
for(int j = 1;j<=n;j++)
{
cin>>a[i][j];
}
dfs(0,0);//此处一定是从矩阵为零的点出发,满足 a[p][q]!=0的条件,由于矩阵从(1,1)开始有值,所以从(0,0)开始肯定不会影响结果。如果从(1,1)开始但是(1,1)处为 1 会导致结果不正确
cout<<endl;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++)
{
if(j!=1) cout<<" ";
if(a[i][j]==3) cout<<"0";
else if(a[i][j]==0) cout<<"2";
else cout<<a[i][j];
}
cout<<endl;
}
}
(二)迷宫
(1)迷宫问题主要注意开始点要在搜索前进行标记,否则容易产生错误。
(2)再搜索过一个点后要还原标记点避免对下一次搜索产生影响。
for(int i = 0;i<4;i++)
{
//选择一个移动方向
int x1 = s.x + x[i];
int y1 = s.y + y[i];
//判断移动方向是否合理
if(x1>=0 && y1>=0 && x1<m && y1<n && map[x1][y1])
{
cnt++;
map[x1][y1] = 0;//可进行移动标记状态为已经过
way[cnt].x = x1;//记录移动路径
way[cnt].y = y1;
dfs(way[cnt]);//在当前可移动的点继续深度搜索可行的移动位置
map[x1][y1] = 1;//将标记状态还原,以免对下一步选择的方向造成影响
cnt--;
}
}
(三)选数问题
这个我感觉有点难理解,还有待提高。
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 1e6;
int a[maxn],n,k,count,ans;
int F(int k)
{
if(k == 1) return 0;
for(int i = 2;i<=sqrt(k);i++)
{
if(k%i == 0) return 0;
}
return 1;
}
void dfs(int sum,int count,int start)
{
if(count == k && F(sum)) ans++;
for(int i = start;i<n;i++)
{
dfs(sum+a[i],count+1,i+1);
}
}
int main()
{
cin>>n>>k;
for(int i = 0;i<n;i++)
cin>>a[i];
dfs(0,0,0);
cout<<ans<<endl;
return 0;
}
今天一天,主要进行了搜索问题的训练,但总体感觉不是很好,有的问题做起来依然吃力,搜索 这一块问题,我相信在寒假过后会有更好的理解。