DFS
int DFS(int t)
{
if(满足输出条件)
{
输出解;
}
else
{
for(int i=1;i<=尝试方法数;i++)
if(满足进一步搜索条件)
{
为进一步搜索所需要的状态打上标记;
DFS(t+1);
恢复到打标记前的状态;//也就是说的{回溯一步}
}
}
}
整个模板有几个地方需要注意:
1.第一个if是符合输出解的条件,第二个if是符合进一步搜索的条件;
2.下一步搜索时,不是使用return search(t+1),直接search(t+1);(新手可能会注意不到这个关键的地方,以至于每次写完不知道为什么只得到一个答案就返回主程序了)
3.for循环之后的if可以是多个;
4.for循环边界,例如:
1>方向是四个,那么边界肯定就是4;(帖主用3,是因为从0开始的)
2>素数环需要尝试1至20,那么边界就是20;
油田问题Oil Deposits(DFS)
Description
GeoSurvComp地质调查公司负责探测地下石油储藏。 GeoSurvComp现在在一块矩形区域探测石油,并把这个大区域分成了很多小块。他们通过专业设备,来分析每个小块中是否蕴藏石油。如果这些蕴藏石油的小方格相邻,那么他们被认为是同一油藏的一部分。在这块矩形区域,可能有很多油藏。你的任务是确定有多少不同的油藏。
Input
输入可能有多个矩形区域(即可能有多组测试)。每个矩形区域的起始行包含m和n,表示行和列的数量,1<=n,m<=100,如果m =0表示输入的结束,接下来是n行,每行m个字符。每个字符对应一个小方格,并且要么是’*’,代表没有油,要么是’@’,表示有油。
Output
对于每一个矩形区域,输出油田的数量。两个小方格是相邻的,当且仅当他们水平或者垂直或者对角线相邻(即8个方向)。
题解
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
char a[105][105];
int mov[8][2]={1,0,-1,0,0,1,0,-1,1,1,-1,-1,1,-1,-1,1};
int m,n;
void dfs(int x,int y)
{
int nextx,nexty,i;
a[x][y]='*';
for(i=0;i<8;i++)
{
nextx=x+mov[i][0];
nexty=y+mov[i][1];
if(nextx>=0 && nextx<m && nexty>=0 && nexty<n)
{
if(a[nextx][nexty]=='@')
{
dfs(nextx,nexty);
}
}
}
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
if(m==0 || n==0) break;
int i,j,sum=0;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf(" %c",&a[i][j]);
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(a[i][j]=='@')
{
dfs(i,j);
sum++;
}
}
}
printf("%d\n",sum);
}
return 0;
}
例题:迷宫问题(DFS)
给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和
终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫
中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
输入样例 输出样例
【数据规模】
1≤N,M≤5
题目描述
输入输出格式
输入格式:
【输入】
第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点
坐标FX,FY。接下来T行,每行为障碍点的坐标。
输出格式:
【输出】
给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方
案总数。
输入输出样例
输入样例#1: 复制
2 2 1
1 1 2 2
1 2
输出样例#1: 复制
1
题解
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
int a[105][105]; //地图
int temp[105][105]; //走过的标记
int mov[4][2]={1,0,-1,0,0,1,0,-1}; //前后左右走
int m,n,t,sx,sy,fx,fy,l,r,nextx,nexty,total=0;
void dfs(int x,int y)
{
if(x==fx && y==fy)
{
total++;
return;
}
else
{
for(int i=0;i<4;i++)
{
nextx=x+mov[i][0];
nexty=y+mov[i][1];//下一步
if(temp[nextx][nexty]==0 && a[nextx][nexty]==1)
{
temp[x][y]=1; //标记已走
dfs(nextx,nexty);
temp[x][y]=0; //回溯
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=1;
scanf("%d%d",&sx,&sy);
scanf("%d%d",&fx,&fy);
for(int i=1;i<=t;i++)
{
scanf("%d%d",&l,&r);
a[l][r]=0; //标记障碍
}
dfs(sx,sy);
printf("%d\n",total);
return 0;
}
洛谷P1162 填涂颜色(DFS)
题目描述
由数字01组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2.例如:6×6的方阵(n=6),涂色前和涂色后的方阵如下:
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
题解
染色法,把全部的0染色成2。然后从外围DFS,将外面的0全部标记。记得在最外围加一圈0,这样外围才可以DFS全部的0,。
代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
int a[105][105]; //染色
int b[105][105]; //地图
int mov[4][2]={1,0,-1,0,0,1,0,-1};
int n,nextx,nexty;
void dfs(int x,int y)
{
if(x<0 || x>n+1 || y<0 || y>n+1 || a[x][y]!=0)
return;
a[x][y]=1;//染色
for(int i=0;i<4;i++)
{
nextx=x+mov[i][0];
nexty=y+mov[i][1];
dfs(nextx,nexty);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%d",&b[i][j]);
if(b[i][j]==0)
a[i][j]=0;
else
a[i][j]=2;
}
dfs(0,0);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]==0)
printf("2 ");
//如果染过色以后i,j那个地方还是0,说明没有搜到,就是周围有墙,当然就是被围住了
else
printf("%d ",b[i][j]);
//因为被染色了,本来没有被围住的水和墙都染成了1,所以就输出b[i][j]
}
printf("\n");
}
return 0;
}
八皇后(DFS)
检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。
输入输出格式
输入格式:
一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。
输出格式:
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
输入样例#1: 复制
6
输出样例#1: 复制
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
题解
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
int a[100];//行
int b[100];//列
int c[100];//左下到右上的对角线
int d[100];//左上到右下的对角线
int total=0,n;
void dfs(int i)
{
if(i>n)
{
if(total<=2) //只要前三个解
{
for(int k=1;k<=n;k++)
printf("%d ",a[k]);
printf("\n");
}
total++;
}
else
{
for(int j=1;j<=n;j++) //尝试可能的位置
{
if(b[j]==0 && c[i+j]==0 && d[i-j+n]==0) //未被占领
{
a[i]=j; //标记第i排是第j个
b[j]=1; //占领该列
c[i+j]=1; //占领左下到右上的对角线
d[i-j+n]=1; //占领左上到右下的对角线
dfs(i+1); //搜索下一行
//回溯 回到上一步 清除标记
b[j]=0; //解放该列
c[i+j]=0; //解放左下到右上的对角线
d[i-j+n]=0; //解放左上到右下的对角线
}
}
}
}
int main()
{
scanf("%d",&n);
dfs(1);
printf("%d\n",total);
}
例题:n个数,每个数有一个,判断是否可以选一些数,使得和为k
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
int a[20];
int n,k;
bool dfs(int i,int sum)
{
//搜索完毕
if(i==n) return k==sum;
//不加上a[i]
if(dfs(i+1,sum)) return true;
//加上a[i]
if(dfs(i+1,sum+a[i])) return true;
return false;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
if(dfs(0,0))
printf("YES\n");
else
printf("NO\n");
return 0;
}
n个数a[i],每个数有b[i]个,判断是否能选一些数使得和为K
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int> p;
typedef long long LL;
int n,k;
int a[105],b[105];
bool dp[105][105];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
memset(dp,false,sizeof(dp));
dp[0][0]=true;
for(int i=0;i<=n;i++)
for(int j=0;j<=k;j++)
for(int kk=0; (kk<=b[i]) && (kk*a[i]<=j) ;kk++)
dp[i+1][j]|=dp[i][j-a[i]*kk];
if(dp[n][k])
printf("YES\n");
else
printf("NO\n");
return 0;
}
BFS
迷宫问题
S为起点,G为终点,#为墙,*为路,求S到G最短距离
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int> p; //这样用更方便
char a[105][105];
int d[105][105];
int ma[4][2]={0,1,0,-1,1,0,-1,0};
int n,m,sx,sy,fx,fy;
int bfs()
{
queue<p>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
d[i][j]=INF;
q.push(p(sx,sy));
d[sx][sy]=0;
while(q.size())
{
p pp;
pp=q.front(); q.pop(); //从队列最上端取出元素
if(pp.first==fx && pp.second==fy) break; //找到
for(int i=0;i<4;i++)
{
int nx=pp.first+ma[i][0];
int ny=pp.second+ma[i][1];
if(nx>=1 && nx<=n && ny>=1 && ny<=m && a[nx][ny]!='#' && d[nx][ny]==INF)
{
q.push( p(nx,ny) ); //继续
d[nx][ny]=d[pp.first][pp.second]+1; //距离加1
}
}
}
return d[fx][fy];
}
int main()
{
int ans;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf(" %c",&a[i][j]);
if(a[i][j]=='S')
{
sx=i;
sy=j;
}
if(a[i][j]=='G')
{
fx=i;
fy=j;
}
}
ans=bfs();
printf("%d\n",ans);
return 0;
}