今天学习了有关搜索的内容,在这里略微的梳理一下。
首先搜索分为广搜和深搜两个区块。广搜的基本思想就是从一个树图的根节点开始,逐层展开进行查找,而深搜就是从根节点出发,找到一个子节点查到底并做上记号,再接下来的搜索中需要对有记号的节点作剪枝的操作,直到完成遍历搜索。其实两种搜索都有大致的模板可以套,但是想要熟练的掌握还得对这两种方法进行更深刻的理解。
接下来各自放一道类体,回顾时能加深理解。
广搜:
Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest.
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.
Input
The input contains multiple test cases.
Each test case include, first two integers n, m. (2<=n,m<=200).
Next n lines, each line included m character.
‘Y’ express yifenfei initial position.
‘M’ express Merceki initial position.
‘#’ forbid road;
‘.’ Road.
‘@’ KCF
Output
For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.
Sample Input
4 4
Y.#@
…
.#…
@…M
4 4
Y.#@
…
.#…
@#.M
5 5
Y…@.
.#…
.#…
@…M.
#…#
Sample Output
66
88
66
代码如下
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <queue>
#include<string.h>
using namespace std;
#define pii pair<int,int>//配对
const int inf=0x3f3f3f3f;
//获取x x=Point.first;就相当于坐标
//获取y y=Point.second;
const int N=200+10;
const int M=10;
char s[N][N];
int sx[M],sy[M];
int n,m,dis[M][N][N];//dis数组是综合x和y的数组,表示距离
int dx[M]= {0,0,1,-1};
int dy[M]= {1,-1,0,0};
void bfs(int id) {
queue<pii>q;//先进先出的队列
q.push(make_pair(sx[id],sy[id]));
dis[id][sx[id]][sy[id]]=0;//id是表明x还是y,剩下的就是他们的坐标
while(!q.empty()) { //q中还有元素
int x=q.front().first,y=q.front().second;//q第一个元素(第一个读入的元素)的x和y的坐标值
q.pop();
for(int i=0; i<4; i++) {
int xx=x+dx[i],yy=y+dy[i];//四个方向都走一遍
if(1<=xx&&xx<=n&&1<=yy&&yy<=m&&dis[id][xx][yy]==inf&&s[xx][yy]!='#') { //确保不回到起点
dis[id][xx][yy]=dis[id][x][y]+1;//储存距离,因此距离加一
q.push(make_pair(xx,yy));//把xx和yy存入最后
}
}
}
}
int main() {
while(scanf("%d %d",&n,&m)!=EOF) {//n行,m个字符
memset(dis,inf,sizeof dis);//把dis数组重置为无穷大
for(int i=1; i<=n; i++) scanf("%s",s[i]+1); //读每行字符,下标从一开始
for(int i=1; i<=n; i++)for(int j=1; j<=m; j++) {
if(s[i][j]=='Y') sx[0]=i,sy[0]=j;//存入结点
if(s[i][j]=='M') sx[1]=i,sy[1]=j;//同上
}
bfs(0),bfs(1);
int res =inf;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(s[i][j]=='@'){//找到了目标点
res=min(res,dis[0][i][j]+dis[1][i][j]);
}
cout<<res*11<<endl;
}
}
深搜:
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1
8
5
0
Sample Output
1
92
10
代码如下
#include<bits/stdc++.h>
using namespace std;
const int N =10+10;
int f[N],vis[N],n,cnt; //vis[i] 代表第i列之前已经被第vis[i]行放置
bool check(int row,int col){ //判断第row行第col列能不能放置棋子
if(vis[col])return false;
for(int i=1;i<=n;i++){ //45°
if(vis[i] && abs(i-col)==abs(vis[i]-row))return false;//
}
return true;
}
void dfs(int now){ //当前准备放置第now行
if(now==n+1){ //是否对答案有贡献
cnt++;
return;
}
for(int i=1;i<=n;i++){
if(check(now,i)){
vis[i]=now; //第i列已经由第now行放置
dfs(now+1); //放置下一行
vis[i]=0; //还原
}
}
}
int main(){
for(n=1;n<=10;n++){
memset(vis,0,sizeof vis);//重置
cnt=0;
dfs(1);
f[n]=cnt;
}
int x;while(scanf("%d",&x)!=EOF){
if(x==0)break;
printf("%d\n",f[x]);
}
}
从搜索开始就要运用有关大量关于二分图的理论,还得多多练习加深理解。