专题1 简单搜索
点击题目名称可以直接跳转
棋盘问题
类似八皇后
#include <iostream>
#include <cstring>
using namespace std;
const int N = 10;
int n, k;
char g[N][N];
bool col[N];//当前列是否摆放棋子
int ans;//方案数量
//当前要去搜索第u行,已经放了t个棋子
void dfs(int u, int t)
{
if(t == k)//当前摆放棋子数量达到要求,方案数+1
{
ans ++;
return ;
}
if(n - u < k - t) return ;//剩余可以摆放棋子的行数小于剩余棋子数量
if(u == n) return ;//所有行搜索完毕
dfs(u + 1, t);//当前行不放棋子,直接搜索下一行
for(int i = 0; i < n; i ++)//循环当前行每一列
if(g[u][i] == '#' && !col[i])//可以放并且该列没放过
{
col[i] = true;
dfs(u + 1, t + 1);
col[i] = false;
}
}
int main()
{
while(cin >> n >> k && n != -1)
{
for(int i = 0; i < n; i ++) cin >> g[i];
//两个初始化
ans = 0; memset(col, 0, sizeof col);
dfs(0, 0);
cout << ans << endl;
}
return 0;
}
Dungeon Master
常规广搜题,不难就是有点麻烦
#include <iostream>
#include <cstring>
using namespace std;
const int N = 35, M = N * N * N;
char g[N][N][N];
int L, R, C;
int x1, x2, y1, y2, z1, z2;
bool st[N][N][N];
int d[N][N][N];
int dx[] = {0, 0, 0, 0, -1, 1}, dy[] = {0, 0, -1, 1, 0, 0}, dz[] = {1, -1, 0, 0, 0, 0};
struct location
{
int x, y, z;
};
void bfs()
{
location q[M], r;
int hh = 0, tt = 0;//手写队列
// q[0] = {x1, y1, z1};估计是POJ没跟上时代,不支持c++新特性
r.x = x1, r.y = y1, r.z = z1;//按照老的来吧
q[0] = r;
d[x1][y1][z1] = 0;
st[x1][y1][z1] = true;
while(hh <= tt)
{
location t = q[hh ++];
int a = t.x, b = t.y, c = t.z;
for(int i = 0; i < 6; i ++)
{
int tx = a + dx[i], ty = b + dy[i], tz = c + dz[i];
if(tx < 1 || tx > R || ty < 1 || ty > C || tz < 1 || tz > L) continue;
if(g[tx][ty][tz] == '#' || st[tx][ty][tz]) continue;
location k;
k.x = tx, k.y = ty, k.z = tz;
q[++ tt] = k;
st[tx][ty][tz] = true;
d[tx][ty][tz] = d[a][b][c] + 1;
if(tx == x2 && ty == y2 && tz == z2) return ;
}
}
}
int main()
{
while(cin >> L >> R >> C && L)
{
for(int k = 1; k <= L; k ++)
{
for(int i = 1; i <= R; i ++)
{
for(int j = 1; j <= C; j ++)
{
cin >> g[i][j][k];
if(g[i][j][k] == 'S') x1 = i, y1 = j, z1 = k;
if(g[i][j][k] == 'E') x2 = i, y2 = j, z2 = k;
}
// getchar();这里不用读空格也可以
}
// getchar();
}
//每次搜索前来个初始化
memset(d, 0, sizeof d), memset(st, 0, sizeof st);
bfs();
if(d[x2][y2][z2] == 0) puts("Trapped!");
else printf("Escaped in %d minute(s).\n", d[x2][y2][z2]);//别忘了这里最后还有个'.'
}
return 0;
}
Catch That Cow
#include <iostream>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int n, k;
int d[N];
int bfs()
{
queue<int> q;
q.push(n);
while(q.size())
{
int t = q.front();
q.pop();
if(t == k) return d[k];
//往左走
if(t - 1 >= 0 && !d[t - 1]) q.push(t - 1), d[t - 1] = d[t] + 1;
//一旦走到k点了就没必要再往右走了
if(t + 1 <= k && !d[t + 1]) q.push(t + 1), d[t + 1] = d[t] + 1;
if(t * 2 <= k + 1 && !d[t * 2]) q.push(t * 2), d[t * 2] = d[t] + 1;
//路径翻倍的时候最多只需要跳到k+1,如果跳到>k+1的地方比如说k+2
//那我们还需要往回跳两次,总共需要三次
//但是我们完全可以一开始不跳两倍的距离直接向右跳一步,然后再让距离翻倍
//这样只需要两步足矣
}
}
int main()
{
cin >> n >> k;
cout << bfs();
return 0;
}
Fliptile
每次触碰一个方格的时候会改变上下左右和自己,用最少的次数将所有方格变成0
本题和 费解的开关 如出一辙,不同的是本题要输出方案而不是方案个数, 费解的开关一题收录在基础篇当中
#include <iostream>
#include <cstring>
using namespace std;
const int N = 20;
int n, m;
int g[N][N], back[N][N];
int res[N][N], tmp[N][N];
int dx[] = {0, -1, 0, 1, 0}, dy[] = {0, 0, 1, 0, -1};
int ans = 1e9;
void turn(int x, int y)
{
for(int i = 0; i < 5; i ++)
{
int a = x + dx[i], b = y + dy[i];
if(a >= 0 && a < n && b >= 0 && b < m)
g[a][b] ^= 1;
}
}
void work()
{
for(int i = 0; i < (1 << m); i ++)
{
memcpy(g, back, sizeof back);
memset(tmp, 0, sizeof tmp);
int cnt = 0;
for(int j = 0; j < m; j ++)
if(i >> j & 1)
{
turn(0, m - j - 1);
cnt ++;
tmp[0][m - j - 1] = 1;
}
for(int j = 0; j < n - 1; j ++)
for(int k = 0; k < m; k ++)
if(g[j][k] == 1)
{
turn(j + 1, k);
cnt ++;
tmp[j + 1][k] = 1;
}
bool f = true;
for(int j = 0; j < m; j ++)
if(g[n - 1][j] == 1)
{
f = false;
break;
}
if(!f) continue;
if(cnt < ans)
{
ans = cnt;
memcpy(res, tmp, sizeof tmp);
}
}
if(ans == 1e9) puts("IMPOSSIBLE");
else
{
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < m; j ++)
cout << res[i][j] << ' ';
cout << endl;
}
}
}
int main()
{
cin >> n >> m;
for(int i = 0; i < n; i ++)
for(int j = 0; j < m; j ++)
{
scanf("%d", &g[i][j]);
back[i][j] = g[i][j];
}
work();
return 0;
}
本题核心在于二进制暴力枚举,暴力枚举就等同于暴力搜索
Find The Multiple
题目虽然说m是不超过200位的十进制数,但是对于所有的n <= 200,我们都能在long long范围内(2^63-1)内找到解,所以我们就按m是在LL范围内来做就行了,不用搞那么复杂,当爆LL以后我们就停止搜索
#include <iostream>
using namespace std;
typedef long long LL;
int n;
bool dfs(LL ans, int digit)
{
if(digit > 19) return false;//LL最多19位
if(ans % n == 0)
{
cout << ans << endl;
return true;
}
if(dfs(ans * 10, digit + 1)) return true;
if(dfs(ans * 10 + 1, digit + 1)) return true;
}
int main()
{
while(cin >> n && n)
{
dfs(1, 1);
}
return 0;
}
这道题不推荐用BFS来写,大概率会T,如果你一定要写BFS,记得也提交一下G++,那个可能不会T