关于模板出处,来自这里
本文仅通过例题对模板的使用进行说明。
#include
#include
#include
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int map[maxn][maxn]; // 坐标范围
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量,(x,y)周围的四个方向
bool CheckEdge(int x,int y){ // 边界条件和约束条件的判断
if(!vst[x][y] && ...) // 满足条件
return 1;
else // 与约束条件冲突
return 0;
}
void dfs(int x,int y){
vst[x][y]=1; // 标记该节点被访问过
if(map[x][y]==G){ // 出现目标态G
...... // 做相应处理
return;
}
for(int i=0;i<4;i++){
if(CheckEdge(x+dir[i][0],y+dir[i][1])) // 按照规则生成下一个节点
dfs(x+dir[i][0],y+dir[i][1]);
}
return; // 没有下层搜索节点,回溯
}
int main(){
......
return 0;
}
某石油勘探公司正在按疾患勘探地下油田资源,在一片长方形地域中工作。他们首先将该地域划分为许多小正方形区域,然后使用勘探设备分别探测在每一小正方形区域内是否有油。含有油的区域被称为油田。如果两个油田相邻(在水平、垂直或对角线相邻),则它们是相同油藏的一部分。油藏可能非常大并可能包含许多油田(油田的个数不超过100)。你的工作是确定在这个长方形地域中包含多少不同的油藏。
输入:输入文件包含一个或多个长方形地域。每个地域的第1行都有两个正整数m和n(1 \leq m,n \leq 100),表示地域的行数和列数。如果m = 0,则表示输入结束;否则此后有m行,每行都有n个字符。每个字符都对应一个正方形区域,字符*表示没有油,字符@表示有油。
输出:对于每个长方形地域,都单行输出油藏的个数。
使用深度优先搜索算法
约束条件为坐标出界限制,对应点是否为油田,标记数组。共3个
#include
using namespace std;
const int maxn=100;
int m,n;
char str[maxn][maxn];
bool vst[maxn][maxn]; // 访问标记
int dir[8][2]={-1,-1,-1,0,-1,1,
0,-1,0,1,1,-1,
1,0,1,1};// 方向向量,(x,y)周围的四个方向
bool check(int x,int y);
void dfs(int x,int y);
int main(){
int count = 0;
cin >> m >> n;
memset(vst,false,sizeof(vst));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
cin >> str[i][j];
}
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if(!vst[i][j] && str[i][j] == '@'){
dfs(i,j);
count++;
}
}
}
cout << count << endl;
return 0;
}
bool check(int x,int y){ // 边界条件和约束条件的判断
if(!vst[x][y] && x >= 0 && x < m && y >= 0 && y < n && str[x][y] == '@'){
return true;
}
else{
return false;
}
}
void dfs(int x,int y){
vst[x][y]= true; // 标记该节点被访问过
for(int i=0;i<8;i++){
if(check(x+dir[i][0],y+dir[i][1])) // 按照规则生成下一个节点
dfs(x+dir[i][0],y+dir[i][1]);
}
return; // 没有下层搜索节点,回溯
}
输入:
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
输出:
2
骑士决定环游世界,其移动方式如下图。骑士的世界是他生活的棋盘,棋盘面积比普通的 8 × 8 8 \times 8 8×8棋盘小,但它任然是长方形的。你能帮助这个骑士做出旅行计划吗?找到一条道路。骑士每次都进入一个方格,可以在棋盘的任意方格上开始和结束。
输入:输入的第1行包含一个正整数 T T T,表示测试用例的数量。每个测试用例的第1行都包含两个 m m m和 n ( 1 ≤ m × n ≤ 26 ) n(1 \leq m \times n \leq 26) n(1≤m×n≤26),表示 m × n m \times n m×n的棋盘,对行数字标识( 1 ∼ m 1 \sim m 1∼m),对列用大写字母标识( A ∼ Z A \sim Z A∼Z)。
输出:每个测试用例的输出都以一个包含“$Scenario #i: $”的行开头,其中i是从1开始的测试用例编号。然后单行输出按字典顺序排列的第1条路径,该路径访问棋盘的所有方块。应通过连接访问方块的名称输出路径,每个方块的名称都由一个大写字母后跟一个数字组成。如果不存在这样的路径,则应该在一行上输出“impossible”。在测试用例之间有个空行。
要注意输出数组path和结束标识flag。
由于输出是先行后列,所以写约束条件时,要把棋盘行列互换
约束条件中上界是小于等于,不是小于,是可以等于的。
回溯时要将之前的点标记为false。
#include
using namespace std;
const int maxn=100;
int m,n;
bool vst[maxn][maxn],flag; // 访问标记
int path[30][2];
int dir[8][2]={-2,-1,-2,1,-1,-2,
-1,2,1,-2,1,2,
2,-1,2,1};// 方向向量,(x,y)周围的四个方向
bool check(int x,int y); //约束条件
bool dfs(int x,int y,int step); //深度优先搜索
int main(){
int T;
cin>>T;
for(int k=1;k<=T;k++)
{
memset(vst,false,sizeof(vst));
cin>>m>>n;
flag=false; //标记是否找到
cout<<"Scenario #"<<k<<":"<<endl;
path[0][0]=1;//从(1,1)开始搜索,行:A
path[0][1]=1;//列1
vst[1][1]=true;//标记已走过
if(dfs(1,1,1)){ //初始状态(1,1),步数:1
for(int i=0;i<m*n;i++)
cout<<char(path[i][0]+'A'-1)<<path[i][1]; //输出路径(行,列)
cout<<endl<<endl;
}
else
cout<<"impossible"<<endl<<endl;
}
return 0;
}
bool check(int x,int y){ // 边界条件和约束条件的判断
if(x >= 1 && x <= n && y >= 1 && y <= m && !vst[x][y] && !flag){
return true;
}
return false;
}
bool dfs(int x,int y,int step){
if(step==n*m) //步数等于棋盘坐标点总数,说明找到了,可以结束
return flag = true; //已经找到
for(int i=0;i<8;i++) // 按照规则生成下一个节点
{
int x2=x+dir[i][0];
int y2=y+dir[i][1];
if(check(x2,y2)) //约束条件
{
vst[x2][y2]= true; //标记走过的坐标
path[step][0]=x2; //记录行
path[step][1]=y2; //记录列
dfs(x2,y2,step+1); //步数加1,继续寻找
vst[x2][y2] = false; //若走不通就回溯
}
}
return flag;
}
约翰希望立即抓住逃亡的牛。当前约翰在节点 N N N,牛在节点 K ( 0 ≤ N , K ≤ 100000 ) K(0 \leq N,K \leq 100000) K(0≤N,K≤100000)时,他们在同一条线上。约翰有两种交通方式:步行和乘车。如果牛不知道有人在追赶自己,原地不动,那么约翰需要多长时间才能抓住牛?
输入:两个整数 N N N和 K K K。
输出:单行输出约翰抓住牛所需的最短时间(以分钟为单位)。
#include
using namespace std;
int n,s;
int dfs(int t); //从n到达位置t的最小步数(深度搜索)
int main(){
scanf("%d %d",&n,&s);
if(n == 0){ //如果n = 0则先走一步到1,否则无法乘车
n++;
printf("%d",dfs(s)+1);
}
printf("%d",dfs(s));
return 0;
}
int dfs(int t){
if(t <= n){ //不能向后乘车,所以只能一步步倒退
return n - t;
}
if(t % 2 == 1){ //如果t为奇数,比较从t-1向前1步到t、从t+1向后1步到t哪种步数少
return min(dfs(t+1)+1,dfs(t-1)+1);
}
else{ //如果t为偶数,比较从t/2乘车到t、从n一步步走哪一种步数少
return min(dfs(t/2)+1,t-n);
}
}
输入:
5 17
输出:
4