搜索基础
八皇后
在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n=8, data[N][10], tt;
int a[10]; // a[y] = x (x,y) 有皇后
int b[10]; // b[y] = 1 (..,y) 有皇后
int c[20], d[20];// 对角线 (x+y), (x-y+n)
void dfs(int x){// dfs(x) : 当前第 x 行应该放皇后
if(x > n){ // 出口
++ tt;
// for(int i=1; i<=n; i++)data[tt][i] = a[i]; return;
// if(tt > 3) return;
cout<<"No."<<tt<<endl;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
cout<<(a[j]==i)<<" \n"[j==n];
}
for(int y=1; y<=n; y++)
if(!b[y] && !c[x+y] && !d[x-y+n]){
b[y]=c[x+y]=d[x-y+n]=1, a[x]=y;
dfs(x+1);
b[y]=c[x+y]=d[x-y+n]=0;
}
}
int main(){
dfs(1);
// int t,x; cin>>t;
// while(t--){
// cin>>x;
// for(int i=1; i<=n; i++) cout<<data[x][i]; cout<<endl;
// }
return 0;
}
八数码
在 3×3 的棋盘上,摆有八个棋子,每个棋子上标有 1 至 8 的某一数字。棋盘中留有一个空格,空格用 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为 123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
string target = "123804765";
int d[][2] = {-1,0,1,0, 0,-1,0,1};
int bfs(string&s){
unordered_map<string,int> mp;
queue<string> q; q.push(s), mp[s]=1;
while(q.size()){
auto u = q.front(); q.pop();
if(u == target) return mp[u]-1;
int p = u.find('0');
for(int i=0; i<4; i++){
int x=p/3+d[i][0], y=p%3+d[i][1];
if(x<0 || x>=3 || y<0 || y>=3) continue;
string v=u;
swap(v[p], v[x*3 + y]);
if(!mp.count(v)) q.push(v), mp[v]=mp[u]+1;
}
}
return -1;
}
int main(){
string s;cin>>s;
cout<<bfs(s);
return 0;
}
红与黑
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向上下左右四个方向的相邻的黑色瓷砖移动。
请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
点击查看代码
#include<iostream>
#include<queue>
using namespace std;
const int N=22;
int n,m,ans,d[][2]={-1,0,1,0,0,-1,0,1};
bool st[N][N];
char s[N][N]; // string s[N];
void dfs(int x,int y){
ans ++, st[x][y] = 1;
for(int i=0; i<4; i++){
int a=x+d[i][0], b=y+d[i][1];
if(a<0||a>=n||b<0||b>=m) continue;
if(st[a][b] || s[a][b]!='.') continue;
dfs(a,b);
}
}
void bfs(int x,int y){
queue< pair<int,int> > q;
q.push({x,y}), st[x][y] = 1, ans++;
while(q.size()){
auto u = q.front(); q.pop(); x = u.first, y = u.second;
for(int i=0; i<4; i++){
int a=x+d[i][0], b=y+d[i][1];
if(a<0||a>=n||b<0||b>=m) continue;
if(st[a][b] || s[a][b]!='.') continue;
q.push({a,b}), st[a][b] = 1, ans ++;
}
}
}
int main(){
cin>>m>>n;
for(int i=0; i<n; i++) cin>>s[i];
for(int i=0; i<n; i++)
for(int j=0; j<m; j++) if(s[i][j]=='@') bfs(i,j);
cout<<ans;
return 0;
}
细胞
一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。
点击查看代码
#include<iostream>
#include<queue>
using namespace std;
const int N=110;
int n,m,ans,d[][2]={-1,0,1,0,0,-1,0,1};
bool st[N][N];
char s[N][N]; // string s[N];
void dfs(int x,int y){
st[x][y] = 1;
for(int i=0; i<4; i++){
int a=x+d[i][0], b=y+d[i][1];
if(a<0||a>=n||b<0||b>=m) continue;
if(st[a][b] || s[a][b]=='0') continue;
dfs(a,b);
}
}
void bfs(int x,int y){
queue< pair<int,int> > q;
q.push({x,y}), st[x][y] = 1;
while(q.size()){
auto u = q.front(); q.pop(); x = u.first, y = u.second;
for(int i=0; i<4; i++){
int a=x+d[i][0], b=y+d[i][1];
if(a<0||a>=n||b<0||b>=m) continue;
if(st[a][b] || s[a][b]=='0') continue;
q.push({a,b}), st[a][b] = 1;
}
}
}
int main(){
cin>>n>>m;
for(int i=0; i<n; i++) cin>>s[i];
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
if(s[i][j]!='0' && !st[i][j]){ ans++; bfs(i,j); }
cout<<ans;
return 0;
}
最少步数
在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。
有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。
他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100×100)的围棋盘上任选两点A、B。A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。
现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n=100, st[N][N];
struct T{ int x,y; };
int d[][2]={-2,-1,-2,1, 2,-1,2,1, -1,-2,1,-2, -1,2,1,2, -2,-2,-2,2, 2,-2, 2,2};
int bfs(int x,int y){
memset(st, 0x00, sizeof st); // 1Bbye = 8bit, 0x00 = 0000 0000
queue<T> q; q.push({x,y}), st[x][y]=1;
while(q.size()){
auto u = q.front(); q.pop();
int x=u.x, y=u.y;
if(x==1 && y==1) return st[x][y]-1;
for(int i=0; i<12; i++){
int a=x+d[i][0], b=y+d[i][1];
if(a<1||a>n||b<1||b>n) continue;
if(st[a][b]) continue;
q.push({a,b}), st[a][b]=st[x][y]+1;
}
}
return -1;
}
int main(){
int x1,y1,x2,y2; cin>>x1>>y1>>x2>>y2;
cout<<bfs(x1,y1)<<endl;
cout<<bfs(x2,y2)<<endl;
return 0;
}
三维迷宫
这题是一个三维迷宫,其中用‘.’表示空地,‘#’表示障碍物,‘S’表示起点,‘E’表示终点,求从起点到终点的最小移动次数,解法和二维的类似,只是在行动时除了东南西北移动外还多了上下。可以上下左右前后移动,每次都只能移到相邻的空位,每次需要花费一分钟,求从起点到终点最少要多久。
点击查看代码