kuangbin带你飞 专题一 简单搜索
1. POJ 1321 棋盘问题
http://poj.org/problem?id=1321
题目类似八皇后 但是加入了障碍物 以及规则为不能同列和同行
我一开始的思路走入了误区 用bool二维数组判断标记
其实我们可以简化问题
将问题看做 在每一行选一个点落下棋子 而保证棋子不在一列 即可
由此确定出dfs的递归参数 一个是行 一个是棋子数 当超出行的时候回溯 在棋子数满足答案时res++并回溯
有一个值得注意的地方 在一行里 可以选择放 也可以选择不放 要注意写出在本行不放的递归函数
char g[10][10];
bool st[10];//这是列的标记 行不需要 因为我们是行行递推下去的
int res, n, k;
void dfs(int dep, int num)//第几行 落子数
{
if(num == k) {
res ++; return;}
if(dep > n) return;//越界
for(int j = 1; j <= n; j++)
{
if(g[dep][j] == '#' && !st[j])
{
st[j] = true;
dfs(dep + 1, num + 1);//落子成功
st[j] = false;
}
}
dfs(dep + 1, num);//在本行没有选到位置落子
}
int main()
{
while(scanf("%d%d", &n, &k) == 2)
{
if(n == -1 && k == -1) break;
res = 0;
for(int i = 1; i <= n; i++)
scanf("%s", g[i] + 1);
ms(st, false);
dfs(1, 0);//从第一行开始 初始落子数0
printf("%d\n", res);
}
return 0;
}
2. POJ 2251 Dungeon Master
http://poj.org/problem?id=2251
这是一个三维地图 读入非常坑爹
反正我觉得题目不能很好地描述题意
思路就是简单的bfs 不过可以向上向下走
调了一下午bug 直接上代码吧
char g[35][35][35];
bool st[35][35][35];
int l, r, c;
int d[6][3]={
{
1,0,0},{
-1,0,0},{
0,1,0},{
0,-1,0},{
0,0,1},{
0,0,-1}};//方向向量
struct point
{
int x, y, z;
int step;
};
bool check(int x, int y, int z)//判断合法
{
if(x < 0 || y < 0 || z < 0 || x >= l || y >= r || z >= c ) return true;
else if(st[x][y][z] == true) return true;
else if(g[x][y][z] == '#') return true;
return false;
}
void bfs(int aa, int bb, int cc)
{
queue<point> q;
point start;
start.x = aa, start.y = bb, start.z = cc, start.step = 0;
q.push(start);
st[aa][bb][cc] = true;
while(q.size())
{
point t = q.front();
q.pop();
if(g[t.x][t.y][t.z] == 'E')//达到出口
{
cout<<"Escaped in "<< t.step <<" minute(s)."<<endl;
return;
}
for(int i = 0; i < 6; i++)
{
int xx = t.x + d[i][0], yy = t.y + d[i][1], zz = t.z + d[i][2];
if(check(xx, yy, zz)) continue;
st[xx][yy][zz] = true;
point tt;
tt.x = xx, tt.y = yy, tt.z = zz;
tt.step = t.step + 1;
q.push(tt);
}
}
cout << "Trapped!" << endl;
return;
}
int main()
{
while(cin >> l >> r >> c)
{
if(l == 0 && r == 0 && c == 0) break;
int aa, bb, cc;
for(int i = 0; i < l; i++)
for(int j = 0; j < r; j++)
{
cin >> g[i][j];//字符串读入
for(int h = 0; h < c; h++)
if(g[i][j][h] == 'S') aa = i, bb = j, cc = h;//起点
}
ms(st, false);
bfs(aa, bb, cc);
}
return 0;
}
3. POJ 3278 Catch That Cow
http://poj.org/problem?id=3278
给出一个起点x 给出一个终点 牛有三种移动方式 前进一格 后退一格 前进x * 2
用BFS的思想可以实现
有一个小点要注意 当n和k的差距很大的时候 需要乘很多次再去回头
所以是有可能有数据会卡在k的很后面的 下面判断合法的时候要注意一下
const int N = 100010;
int dis[N];
bool st[N];
struct node
{
int x, step;
};
queue<node> q;
void bfs(int x)
{
node h;
h.x = x, h.step = 0;
ms(st, false);
q.push(h);
st[h.x] = true;
while(q.size())
{
node t = q.front();
q.pop();
if(t.x == k)
{
cout << t.step << endl;
return;
}
for(int i = 0; i < 3; i++)//枚举三种移动方式
{
int xx;
if(i == 0) xx = t.x + 1;
else if(i == 1) xx = t.x - 1;
else if(i == 2) xx = t.x * 2;
if(xx >= 0 && xx <= N && !st[xx])//之前错的是 xx <= k + 10 考虑不周
{
node next;
next.x = xx, next.step = t.step + 1;
q.push(next);
st[xx] = true;
}
}
}
}
int main()
{
cin >> n >> k;
bfs(n);
return 0;
}
4. POJ 3279 Fliptile
http://poj.org/problem?id=3279
是蓝书中的改编版 同样的二进制枚举翻转牌子 但是这题要我们输出的是翻转过的位置 并且还是按字符串的字典序
二维矩阵压缩到字符串的话 这跟二进制枚举字典序其实是一样的 因为二进制枚举是先枚举第一个点翻转 然后
用ans数组记录下翻转的位置 当第一次翻转成功就break直接输出ans数组
如果没有一次翻转成功的话 IMPOSSIBLE
每次枚举的时候要记得清空ans数组 要用一个数组复制原数组翻转 是为了回溯
int m, n, flag;//地图 标记
int g[20][20], b[20][20], ans[20][20];
int d[5][2] = {
{0, 0}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}};
void turn(int x, int y)//把0 变成1 把1 变成0
{
for(int i = 0; i < 5; i++)
{
int xx = x + d[i][0], yy = y + d[i][1];z
if(~xx && ~yy && xx < n && yy < m) b[xx][yy] ^= 1;
}
}
bool check()//通过最后一行判断是否翻转完成
{
for(int i = 0; i < m; i++)
if(b[n - 1][i] == 1) return false;
return true;
}
int main()
{
cin >> n >> m;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
cin >> g[i][j];
for(int i = 0; i < (1 << m); i++)//二进制枚举
{
memcpy(b, g, sizeof g);
ms(ans, 0);
for(int j = 0; j < m; j++)
if( i >> j & 1) turn(0, j), ans[0][j] = 1;//枚举第一行
for(int j = 0; j < n - 1; j++)
for(int k = 0; k < m; k++) if(b[j][k]) turn(j + 1, k), ans[j + 1][k] = 1;
if(check())
{
flag = 1;
break;
}
}
if(flag)
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
cout << ans[i][j] << " ";
cout << endl;
}
}
else cout << "IMPOSSIBLE" << endl;
return 0;
}
5. POJ 1426 Find The Multiple
http://poj.org/problem?id=1426
翻译一下这个让人看不懂的题干
给定正整数n 请找出任意一个由0和1组成的是n的倍数的数 答案最大不超过200位数
看起来很吓人 其实不会超出LL的范围 那我们直接枚举这个二进制数 判断是否为n的倍数即可
LL ans[1000000];
int main()
{
int n;
while(cin >> n)
{
if(n == 0) break;
if(n == 1) {
cout << "1" << endl;continue;}
ans[1] = 1;
for(int i = 2; i; i++)
{
ans[i] = ans[i / 2] * 10 + i %

最低0.47元/天 解锁文章
139

被折叠的 条评论
为什么被折叠?



