递归和排列
子集生成和组合
BFS
BFS广度优先搜索或者宽度优先搜索
BFS和队列
BFS=队列
#include<bits/stdc++.h>
using namespace std;
char room[23][23];
int dir[4][2] = {{-1, 0},{0,-1},{1,0},{0,1}};
int Wx, Hy, num;
#define CHECK(x,y)(x<Wx && x>=0 && y>=0 && y<Hy)
struct node{int x,y;};
void BFS(int dx, int dy){
num = 1;
queue<node>q;
node start, next;
start.x = dx;
start.y = dy;
q.push(start);
while(!q.empty()){
start = q.front();
q.pop();
//cout<<start.x<<' '<<start.y<<endl;
for(int i = 0; i < 4; i++){ //按左上右下顺时针搜索
next.x = start.x + dir[i][0];
next.y = start.y + dir[i][1];
if(CHECK(next.x,next.y) && room[next.x][next.y] == '.'){
room[next.x][next.y] = '#'; //进队后标记已处理
num++;
q.push(next);
}
}
}
}
int main(){
int x, y, dx, dy;
while(cin>> Wx>> Hy){ //Wx行,Hy列
if(Wx == 0 && Hy == 0) break; //结束
for(y = 0; y<Hy;y++){
for(x = 0; x<Wx;x++){
cin>> room[x][y];
if(room[x][y] == '@'){ //读入起点
dx = x;
dy = y;
}
}
}
num = 0;
BFS(dx, dy);
cout<<num<<endl;
}
return 0;
}
输入
5 4
....#
.....
#@...
.#..#
0 0
输出
15
例题
poj 3278
poj 1426
poj 3126
poj 3414
hdu 1240
hdu 4460
八数码问题和状态图搜索
#include<bits/stdc++.h>
using namespace std;
const int LEN = 362880;
struct node{
int state[9];
int dis;
} ;
int dir[4][2] = {{-1, 0},{0,-1},{1,0},{0,1}};
int visited[LEN] = {};
int start[9];
int goal[9];
long int factory[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
bool Cantor(int str[], int n){
long result = 0;
for(int i = 0; i < n; i++){
int counted = 0;
for( int j = i+1; j < n; j++){
if(str[i] > str [j]) ++counted;
}
result += counted * factory[n-i-1];
}
if(!visited[result]){
visited[result] = 1;
return 1;
}
else return 0;
}
int bfs(){
node head;
memcpy(head.state,start,sizeof(head.state));
head.dis=0;
queue<node> q;
Cantor(head.state,9);
q.push(head);
while(!q.empty()){
head=q.front();
q.pop();
int z;
for(z = 0; z< 9;z++)
if(head.state[z] == 0)break;
int x = z%3;
int y = z/3;
for(int i = 0; i < 4; i++){
int newx = x+dir[i][0];
int newy = y+dir[i][1];
int nz = newx + 3 * newy;
if(newx >= 0&& newx<3 &&newy>=0&&newy<3){
node newnode;
memcpy(&newnode, &head, sizeof(struct node));
swap(newnode.state[z],newnode.state[nz]);
newnode.dis++;
if(memcmp(newnode.state,goal,sizeof(goal))==0) return newnode.dis;
if(Cantor(newnode.state, 9)) q.push(newnode);
}
}
}
return -1;
}
int main(){
for(int i = 0; i < 9; i++) cin>>start[i];
for(int i = 0; i < 9; i++) cin>>goal[i];
int num = bfs();
if(num != -1) cout<<num<<endl;
else cout<<"Impossible"<<endl;
return 0;
}
poj 1077;
BFS和A*算法
在搜索最短距离时,如果(障碍物或相邻点距离不同)绕路更近,A*算法优化了BFS。
双向广搜
双向广搜是BFS的增强版
DFS
DFS和递归
POJ 3984 迷宫问题
题目:
Description
定义一个二维数组:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。
Sample Input
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
思路:
迷宫是一个5 × 5的二维数组,搜索起来不会很复杂,也不会超时。从左上角(0, 0)位置开始,上下左右进行搜索,可以定义一个方向数组,代表上下左右四个方向,使用方向数组,可以使一个点上下左右移动。对于数组中的每个元素用结构体来存储,除了有x,y成员外,还要定义pre成员,用来表示从左上角到右下角的最短路径中每个元素的前一个元素的下标,即保存路径,方便后面的输出。通过广度搜索借助队列进行操作,当中要注意1.搜索的元素是否在迷宫内;2.是否可行(其中1是墙壁不能走,0可以走)。我们可以把已走过的路标记为1,这样能保证路径最短(因为广度优先搜索,只会离初始点的步数一步步增多。如果之后发现遇到了已走过的点,那肯定是从之前已走过的点那边走最短,而不是从之后发现的点走最短啊),直到搜索到右下角(4, 4),问题就解决了。输出路径即可。
水池数目
#include<bits/stdc++.h>
using namespace std;
int mp[100][100],m,n,t;
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
void dfs(int dx,int dy){
mp[dx][dy]=0;
for(int i = 0; i<4;i++){
int nx=dx+dir[i][0];
int ny=dy+dir[i][1];
if (nx>=0 && nx <n && ny>=0 && ny<m && mp[nx][ny]==1){
mp[nx][ny] = 0;
dfs(nx,ny);
}
}
}
int main(){
cin>>t;
while(t--){
cin>>m>>n;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++) cin>>mp[i][j];
}
int count = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(mp[i][j] == 1){
dfs(i, j);
count++;
}
}
}
cout<<count<<endl;
}
return 0;
}