[kuangbin神带你飞]专题一 简单搜索

A - 棋盘问题

我的做法是从上到下,从左到右扫描,每次扫描到一个可用的棋盘(‘#’),当前行和当前列都不能再有可用的棋盘(‘#’),然后进入下一层并往后继续扫描,一旦扫描到k个可用的棋盘(‘#’),就得到一种方案,递归得到所有的方案数即得到本题的解。

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/27 21:45:57
 * File Name   : 1_A.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 10
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int n,k;   
int ans;
int G[MAX_N][MAX_N];
int vis[MAX_N][MAX_N];

void dfs(int row, int col, int cnt){
    if(cnt == k){
        ans++;
        return;
    }else{
        for(int x = row;x < n; x++){
            for(int y = (x==row)?col:0;y < n; y++){
                if(!vis[x][y] && G[x][y]){
                    //如果可行
                    //遍历下一个位置
                    int _vis[MAX_N][MAX_N];
                    //复制之前状态
                    
                    for(int i = 0;i < n; i++){
                        for(int j = 0;j < n; j++){
                            _vis[i][j] = vis[i][j];
                        }
                    }
                    for(int j = 0;j < n; j++){
                        //清除下一个位置的标记
                        vis[j][y] = 1;
                        vis[x][j] = 1;
                    }
                    dfs(x, y, cnt+1);
                    //状态还原
                    for(int i = 0;i < n; i++){
                        for(int j = 0;j < n; j++){
                            vis[i][j] = _vis[i][j];
                        }
                    }
                }
            }
        }
    }
}
int main() {
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);
    while(cin >> n >> k){
        ans = 0;
        if(n == -1 && k == -1) break;
        memset(G, 0, sizeof(G));
        memset(vis, 0, sizeof(vis));
        for(int i = 0;i < n; i++){
            for(int j = 0;j < n; j++){
                char c;
                cin >> c;
                if(c == '#') G[i][j] = 1;
            }
        }
        dfs(0,0,0);
        cout << ans << endl;
    }
    return 0;
}

B - Dungeon Master
本题从‘S’出发,每次可以选择东南西北上下6个方向中可走的位置走一步(用dx,dy,dz数组控制),BFS可以确保第一个搜到‘E'的解为最少步数解。代码如下:

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/28 9:14:26
 * File Name   : 1_B.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define MAX_N 35
char G[MAX_N][MAX_N][MAX_N];
int L, N, M;
int sx,sy,sz,gx,gy,gz;               //起点,终点
int ans;                             //答案
int d[MAX_N][MAX_N][MAX_N];          //最短距离
//六个方向
const int dx[6] = {1,-1,0,0,0,0};   
const int dy[6] = {0,0,1,-1,0,0};
const int dz[6] = {0,0,0,0,1,-1};
struct node{
    int x, y, z;
    node(int _x, int _y, int _z):x(_x),y(_y),z(_z){}
};
bool ok(int x, int y, int z){
    //如果下一步可以走
    if(d[x][y][z] == INF && x >= 0 && x < N && y >= 0 && y < M && z >= 0 && z < L && G[x][y][z] != '#')
        return true;
    return false;
}
int bfs(int x, int y, int z){
    queue<node> que;
    //while(que.size()) que.pop();
    que.push(node(x,y,z));
    d[x][y][z] = 0;
    //bfs
    while(que.size()){
        node q = que.front(); que.pop();
        if(G[q.x][q.y][q.z] == 'E') break;   //如果可以逃出
        for(int i = 0;i < 6; i++){
            int _x = q.x + dx[i];
            int _y = q.y + dy[i];
            int _z = q.z + dz[i];
            if(ok(_x, _y, _z)){
                //如果可以下一步,入队,记录最短距离
                que.push(node(_x, _y, _z));
                d[_x][_y][_z] = d[q.x][q.y][q.z]+1;
            }
        }
    }
    return d[gx][gy][gz];
}
int main() {
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);
    while(cin >> L >> N >> M){
        if(!L && !N && !M) break;
        ans = INF;
        sx = sy = sz = gx = gy = gz = 0;
        //构图,确定终点和起点
        memset(d, 0x3f, sizeof(d));
        memset(G, 0, sizeof(G));
        for(int k = 0;k < L; k++){
            for(int i = 0;i < N; i++){
                for(int j = 0;j < M; j++){
                    cin >> G[i][j][k];
                    if(G[i][j][k] == 'S'){
                        //起点
                        sx = i;sy = j; sz = k;
                    }
                    if(G[i][j][k] == 'E'){
                        //终点
                        gx = i;gy = j; gz = k;
                    }
                }
            }
        }
        ans = bfs(sx,sy,sz);
        if(ans == INF){
            //如果不能到达
            printf("Trapped!\n");
        }else{
            //如果可以
            printf("Escaped in %d minute(s).\n", ans);
        }
    }   
    return 0;
}

C - Catch That Cow

只不过是改成了一维的BFS,应该是更简单了。只不过只有往前一步,往后一步,和跳跃(2*X)。具体见代码~~

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/28 11:19:54
 * File Name   : 1_C.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 100100
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int N, K;                         //出发,终点
int d[MAX_N];                     //最短距离
const int dx[] = {-1,1,2};        //当为2时,变成X * d[i]
int bfs(){
    queue<int> que;
    que.push(N);
    d[N] = 0;                                     //初始化
    while(que.size()){
        int x = que.front(); que.pop();
        if(x == K) break;                         //到达终点,结束
        for(int i = 0;i < 3; i++){
            int _x;                                 
            if(dx[i] == 2) _x = x * dx[i];        //跳跃
            else _x = x + dx[i];                  //前进或者后退一步
            if(_x >= 0 && _x < 100001 && d[_x] == INF){
                //符合条件,往下走
                d[_x] = d[x] + 1;
                que.push(_x);
            }
        }
    }
    return d[K];
}
int main() {
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);
    while(cin >> N >> K){
        memset(d, 0x3f, sizeof(d));
        int ans = bfs();
        cout << ans << endl;
    }
    return 0;
<span style="color:#FF0000;">}
</span>
D - Fliptile

给定一个N*M的网格,每个网格里有一个数字,0或者1,要求你翻转尽量少的网格,使得所有网格的数字都变为0,对于某一个网格进行翻转操作时,与它有公共边的网格全部会被翻转。

枚举第一行的状态,只要第一行的状态确定了,可以往下推出其余状态。

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/28 15:43:04
 * File Name   : 1_D.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 20
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int M,N;
int a[MAX_N][MAX_N], b[MAX_N][MAX_N], ans[MAX_N][MAX_N];
bool check(int s){
    for(int i = 0;i < N; i++){
        //更新第一行
        if(s & (1<<i)){
            ans[0][i] = 1;           
            b[0][i] ^= 1;                  
            if(1 < M)    b[1][i] ^= 1;       //下
            if(i-1 >= 0) b[0][i-1] ^= 1;     //左
            if(i+1 < M)  b[0][i+1] ^= 1;     //右
        }
    }
    for(int i = 1;i < M; i++){
        for(int j = 0;j < N; j++){
            if(b[i-1][j]){
                ans[i][j] = 1;
                b[i][j] ^= 1;
                //更新上下左右
                b[i-1][j] ^= 1;
                if(i+1 < M)  b[i+1][j] ^= 1;
                if(j-1 >= 0) b[i][j-1] ^= 1;    
                if(j+1 < N)  b[i][j+1] ^= 1;
            }   
        }   
    }
    for(int i = 0;i < N; i++){
        if(b[M-1][i]) return false;
    }
    return true;
}
void print(){
    for(int i = 0;i < M; i++){   
        for(int j = 0;j < N; j++){
            printf("%d%c", ans[i][j], (j == N-1)?'\n': ' ');
        }
    }
}
int main() {
    //freopen("in.txt", "r", stdin);
    //cin.tie(0);
    //ios::sync_with_stdio(false);
    scanf("%d%d", &M, &N);
    for(int i = 0;i < M; i++){
        for(int j = 0;j < N; j++){
            scanf("%d", &a[i][j]);
        }
    }
    int ok = 0;
    for(int i = 0;i < (1<<N); i++){
        //枚举第一行的所有状态
        memcpy(b, a, sizeof(a));
        memset(ans, 0, sizeof(ans));
        if(check(i)){
            ok = 1;        
            print();
            break;
        }
    }
    if(!ok)
        printf("IMPOSSIBLE\n");
    return 0;
}


E - Find The Multiple

在1~200的数据里,结果不会有100位的。。所以用unsigned long long就可以存下

直接搜第k*10和k*10+1就可以

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/28 16:55:14
 * File Name   : 1_E.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
const int INF = 0x3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<int, int> P;
bool ok;
void dfs(ULL k, int n, int dep){
    if(ok)                      //当已经查找到返回
        return ;
    if(!(k % n)){ 
        cout << k << endl;     //找到输出
        ok = true;              
        return ;
    }
    if(dep == 19){
        //最大就19层
        //递归回溯
        return ;
    }
    //想要数字里只存在1和0只递归这两种就可以
    dfs(k * 10, n, dep+1);            //k * 10
    dfs(k * 10 + 1, n, dep+1);               //k * 10 + 1
}
int main(){
    //freopen("in.txt", "r", stdin);
    //cin.tie(0);
    //ios::sync_with_stdio(false);
    int n;
    while(cin >> n){
        if(!n) break;
        ok = false;
        dfs(1, n, 0);
    }
    return 0;
}

F - Prime Path

1.先将两个数每一位进行分离,保存起来

2.用bfs来解,把4位数字看成一个状态,每一位数可以变换9次,而且有4位数,每变换一个位,检查是否是素数并且没有被访问过,如果是,放入队列。如果可以达到目标状态,那么输出最少的步数,直到队列为空也没有找到,返回无解

题解链接



J - Fire!

需要两个BFS,第一个寻找每块空地被蔓延到的时间,第二个寻找人离开这里的最短路径,如果必须被烧到则输出IMPOSSIBLE

需要注意的就是人只有一个出发点,但是可以有N个着火点,N也可以为0,WA了无数次总结出来的。。

我这里直接用的G[MAX_N][MAX_N]来保存的地图。如果是墙,则为-1,是空地设置为INF,第一次bfs之后,G里面保存的是火到达每一个空地的时间(墙还是-1)

所以在第二次bfs人逃跑的时候,只要这个人可以赶在这个点着火之前通过就可以

题解链接



K - 迷宫问题

设置一个数组pre[i] 表示i的路径前驱是pre[i],只不过类型是坐标形式。pre得到的是从终点到起点的路径,输出需要借助栈反序

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/29 12:53:29
 * File Name   : 1_K.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 30
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int maze[10][10];
int d[MAX_N][MAX_N];
map<P, P> pre;    //i的前驱是pre[i];
const int dx[] = {0,0,-1,1};
const int dy[] = {1,-1,0,0};
void bfs(){
    memset(d, 0x3f, sizeof(d));
    queue<P> que;
    que.push(P(0, 0));
    d[0][0] = 0;
    while(que.size()){
        P q = que.front(); que.pop();
        for(int i = 0;i < 4; i++){
            int x = q.first + dx[i];
            int y = q.second + dy[i];
            if(!maze[x][y] && d[x][y] == INF && x >=0 && x < 5 && y >= 0 && y < 5){
                d[x][y] = d[q.first][q.second] + 1;
                que.push(P(x, y));
                //路径前驱
                pre[P(x, y)] = P(q.first, q.second);
            }
        }
    }
}
int main() {
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);
    memset(maze, 0, sizeof(maze));
    for(int i = 0;i < 5; i++){
        for(int j = 0;j < 5; j++){
            cin >> maze[i][j];
        }
    }
    bfs();
    //路径输出
    P s(4,4);
    stack<P> _stack;
    while(!(s.first == 0 && s.second == 0)){
        _stack.push(P(s.first, s.second));
        s = pre[s];
    }
    _stack.push(P(0, 0));
    while(_stack.size()){
        P ans = _stack.top(); _stack.pop();
        cout <<"("<< ans.first <<", "<< ans.second <<")"<<endl;
    }
    //cout << d[4][4] << endl;
    return 0;
}

M-非常可乐

就是用队列模拟倒水的情况。。

若s中有水,那么有两种情况,可以给n倒,也可以给m倒  

         1.给n倒 有两种情况

                A.可以倒满

                B.倒不满

         2.给m倒 有两种情况

                A.可以倒满

                B.倒不满

若n中有水。。m中有水,还是上面相同的倒法,输出最少步数

题解链接



N - Find a way
1.用BFS分别找出‘Y’和‘M’到每个‘@’点的最小时间。
2.枚举每个‘@’的位置,并找出到‘Y’点、‘M’点之和的最短距离。

3.输出第2步求的的最短距离乘以11.

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/29 16:29:39
 * File Name   : 1_N.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define MAX_N 220
int n, m;
char G[MAX_N][MAX_N];
P KFC[MAX_N];
int Y_d[MAX_N][MAX_N];
int M_d[MAX_N][MAX_N];
int d[MAX_N][MAX_N];

const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};


void bfs(int x, int y,int flag){
    memset(d, 0x3f, sizeof(d));
    d[x][y] = 0;
    queue<P> que;
    que.push(P(x, y));
    while(que.size()){
        P q = que.front(); que.pop();
        for(int i = 0;i < 4; i++){    
            int _x = q.first + dx[i];
            int _y = q.second + dy[i];
            if(d[_x][_y] == INF && _x >= 0 && _x < n && _y >= 0 && _y < m && G[_x][_y] != '#'){
                d[_x][_y] = d[q.first][q.second] + 1;
                que.push(P(_x, _y));
            }
        }
    }
    if(flag){
        memcpy(M_d, d, sizeof(d));      
    }else{
        memcpy(Y_d, d, sizeof(d));
    }
}
int main() {
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);     
    while(cin >> n >> m){
        memset(Y_d, 0x3f, sizeof(Y_d));
        memset(M_d, 0x3f, sizeof(M_d));
        for(int i = 0;i < n; i++){
            for(int j = 0;j < m; j++){
                cin >> G[i][j];       
            }
        }
        int cnt = 0;                    //KFC' count
        for(int i = 0;i < n; i++){
            for(int j = 0;j < m; j++){
                if(G[i][j] == 'Y'){
                    bfs(i, j, 0);
                }
                if(G[i][j] == 'M'){
                    bfs(i, j, 1);
                }
                if(G[i][j] == '@'){
                    KFC[cnt].first = i;
                    KFC[cnt++].second = j;
                }
            }
        }
        int ans = INF;
        for(int i = 0;i < cnt; i++){
            ans = min(ans, M_d[KFC[i].first][KFC[i].second] + Y_d[KFC[i].first][KFC[i].second]);
        }
        cout << ans * 11 << endl;
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值