[bin神带我飞系列]专题一 搜索入门

搜索入门练练练!

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=65959#overview

感谢bin神带我第一次飞飞飞。


A:

题意:

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。- - 中文题。

解析:

每行往下dfs,水。

代码:

#include <stdio.h>
#include <string.h>

const int maxn = 10 + 10;
char g[maxn][maxn];
bool vis[maxn];
int ans;
int n;

void dfs(int row, int k)
{
    if (row == n)
    {
        if (k == 0)
        {
            ans++;
        }
        return ;
    }
    dfs(row + 1, k);
    for (int i = 0; i < n; i++)
    {
        if (g[row][i] == '#' && !vis[i])
        {
            vis[i] = true;
            dfs(row + 1, k - 1);
            vis[i] = false;
        }
    }
    return;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int k;
    while (~scanf("%d%d", &n, &k))
    {
        if (n == -1 && k == -1)
            break;
        for (int i = 0; i < n; i++)
        {
            scanf("%s", g[i]);
        }
        memset(vis, false, sizeof(vis));
        ans = 0;
        dfs(0, k);
        printf("%d\n", ans);
    }
    return 0;
}

B:

题意:

3D迷宫,bfs。

解析:

加一维表示空间就好惹,从bin神那里学来的step -1 标记法,再也不用vis担心我的搜索重复了。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 30 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int dir[][3] = {{0, -1, 0}, {0, 1, 0}, {-1, 0, 0}, {1, 0, 0}, {0, 0, -1}, {0, 0, 1}};
int l, r, c;
int g[maxn][maxn][maxn];
int dp[maxn][maxn][maxn];

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 (0 <= x && x < r && 0 <= y && y < c && 0 <= z && z < l && g[z][x][y] != '#')
        return true;
    return false;
}

int bfs(int sx, int sy, int sz, int ex, int ey, int ez)
{
    memset(dp, -1, sizeof(dp));
    queue<Node> q;
    q.push(Node(sx, sy, sz));
    dp[sx][sy][sz] = 0;

    while (!q.empty())
    {
        Node now = q.front();
        q.pop();
        int x = now.x;
        int y = now.y;
        int z = now.z;
        //cout << x << " " << y << " " << z << endl;
        if (x == ex && y == ey && z == ez)
        {
            return dp[x][y][z];
        }
        for (int i = 0; i < 6; i++)
        {
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
            int nz = z + dir[i][2];
            if (ok(nx, ny, nz))
            {
                if (dp[nx][ny][nz] == -1)
                {
                    dp[nx][ny][nz] = dp[x][y][z] + 1;
                    q.push(Node(nx, ny, nz));
                }
            }
        }
    }
    return -1;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    while (~scanf("%d%d%d", &l, &r, &c))
    {
        if (!l && !r && !c)
            break;
        getchar();
        for (int i = 0; i < l; i++)
        {
            for (int j = 0; j < r; j++)
            {
                for (int k = 0; k < c; k++)
                {
                    scanf("%c", &g[i][j][k]);
                }
                getchar();
            }
            getchar();
        }
        int sx, sy, sz, ex, ey, ez;
        for (int i = 0; i < l; i++)
        {
            for (int j = 0; j < r; j++)
            {
                for (int k = 0; k < c; k++)
                {
                    if (g[i][j][k] == 'S')
                    {
                        sx = j;
                        sy = k;
                        sz = i;
                    }
                    if (g[i][j][k] == 'E')
                    {
                        ex = j;
                        ey = k;
                        ez = i;
                    }
                }
            }
        }
       // cout << sx << " " << sy << " " << sz << " " << endl;cout << ex << " " << ey << " " << ez << " " << endl;
        int ans = bfs(sx, sy, sz, ex, ey, ez);
        if (ans == -1)
        {
            printf("Trapped!\n");
        }
        else
        {
            printf("Escaped in %d minute(s).\n", ans);
        }
    }
    return 0;
}

C:

题意:

抓牛,牛在一个位置,你在一个位置,你的坐标可以+1 or -1 or *2,最短抓到牛的时间。

解析:

bfs,加了一点点剪枝。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int step[maxn];

int bfs(int n, int k)
{
    memset(step, -1, sizeof(step));
    queue<int> q;
    q.push(n);
    step[n] = 0;

    while (!q.empty())
    {
        int now = q.front();
        q.pop();

        if (now == k)
            return step[now];
        int next;
        /// - 1
        next = now - 1;
        if (0 <= next && step[next] == -1)///剪枝
        {
            step[next] = step[now] + 1;
            q.push(next);
        }
        /// + 1
        next = now + 1;
        if (next < maxn && step[next] == -1)///剪枝
        {
            step[next] = step[now] + 1;
            q.push(next);
        }
        /// * 2
        next = now * 2;
        if (next < maxn && step[next] == -1)///剪枝
        {
            step[next] = step[now] + 1;
            q.push(next);
        }
    }
    return 0;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int n, k;
    while (~scanf("%d%d", &n, &k))
    {
        printf("%d\n", bfs(n, k));
    }
    return 0;
}

D:

题意:

题目看了半天才懂,给一个n*m的01矩阵,0代表白,1代表黑。

现在要你来翻转他们,每次翻转一个点,这个点的上下左右的点都会翻转,1翻成0,0翻转成1。

现在要你求最短的翻转次数,使得这个矩阵全白,that means 全为0。

解析:

参考了网上一些大牛的做法。

首先,如果一个点翻转两次和没翻是没差的,所以一个点最多只翻一次。

n,m并不大,只有15,所以用状态压缩把010101的状态保存下来,然后暴力下去。

为了保证字典序最小,从第一行的右向左开始暴,每次第一行确定了以后,剩下的行的状态也就随之确定了(想一想,为什么)。

然后全部搞完以后,判断最后一行是否全为0,若是,则此次翻转成功,更新最小值,就好啦。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 15 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
int cnt;
int g[maxn][maxn];
int t[maxn][maxn];
int flipNum[maxn][maxn];

void flip(int x, int y)
{
    cnt++;
    flipNum[x][y] = 1;
    t[x][y] ^= 1;
    for (int i = 0; i < 4; i++)
    {
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if (0 <= nx && nx < n && 0 <= ny && ny < m)
        {
            t[nx][ny] ^= 1;
        }
    }
    return;
}

bool ok(int state)
{
    cnt = 0;
    memcpy(t, g, sizeof(t));
    for (int i = 0; i < m; i++)
    {
        if (state & (1 << (m - i - 1)))
        {
            flip(0, i);
        }
    }

    for (int i = 1; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (t[i - 1][j])
            {
                flip(i, j);
            }
        }
    }

    for (int i = 0; i < m; i++)
    {
        if (t[n - 1][i])
        {
            return false;
        }
    }
    return true;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    while (~scanf("%d%d", &n, &m))
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                scanf("%d", &g[i][j]);
            }
        }
        int ans = n * m + 1;
        int state = -1;
        memset(flipNum, 0, sizeof(flipNum));
        for (int i = 0; i < (1 << m); i++)
        {
            if (ok(i) && cnt < ans)
            {
                ans = cnt;
                state = i;
            }
        }
        memset(flipNum, 0, sizeof(flipNum));
        if (state != -1)
        {
            ok(state);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    printf("%d%c", flipNum[i][j], j < m - 1 ? ' ' : '\n');
                }
            }
        }
        else
        {
            printf("IMPOSSIBLE\n");
        }
    }
    return 0;
}

E:

题意:

给一个数n,求这个数的倍数里面,只含0、1的数。

解析:

看别人暴了一个20位的数,用unsigned __int64水过。

小u的博客上有数论的解法。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define UI64 unsigned __int64

using namespace std;
const int maxn = 15;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int n;
bool flag;

void dfs(UI64 t, int dep)
{
    if (flag)
        return;
    if (dep >= 20)
        return;
    if (t % n == 0)
    {
        flag = true;
        printf("%I64u\n", t);
        return;
    }
    dfs(t * 10, dep + 1);
    dfs(t * 10 + 1, dep + 1);
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    while (scanf("%d", &n) && n)
    {
        flag = false;
        dfs(1, 0);
    }
    return 0;
}

F:

题意:

素数路径,给俩素数,每次只能改变一个位置的数,并且改变成的这个数也要是素数,求最少变换次数。

解析:

bfs,素数处理方法,刚开始用数论里面总结的素数打表法竟然出错了,我。。。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 1e4 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int prime[maxn];
bool isPrime[maxn];
int nprime;
void primeTable()
{
    int i,j;
    for(i = 1000; i <= maxn; i++)
    {
        for(j = 2; j < i; j++)
            if(i % j == 0)
            {
                isPrime[i] = false;
                break;
            }
        if(j == i)
            isPrime[i] = true;
    }
}

bool flag;
int step[maxn];
int bfs(int s, int e)
{
    int num[5];
    memset(step, -1, sizeof(step));

    queue<int> q;
    q.push(s);
    step[s] = 0;

    while (!q.empty())
    {
        int now = q.front();
        q.pop();
        if (now == e)
        {
            flag = true;
            return step[now];
        }
        int t = now;
        for (int i = 0; i < 4; i++)
        {
            num[i] = t % 10;
            t /= 10;
        }
        for (int i = 0; i < 4; i++)
        {
            t = num[i];
            for (int j = 0; j <= 9; j++)
            {
                if (j != t)
                {
                    num[i] = j;
                    int next = 0;
                    for (int k = 3; k >= 0; k--)
                        next = next * 10 + num[k];
                    if (step[next] == -1 && isPrime[next])
                    {
                        step[next] = step[now] + 1;
                        q.push(next);
                    }
                }
                num[i] = t;
            }
        }
    }
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    primeTable();
    while (ncase--)
    {
        int s, e;
        scanf("%d%d", &s, &e);
        flag = false;
        int ans = bfs(s, e);
        if (flag)
            printf("%d\n", ans);
        else
            printf("Impossible\n");
    }
    return 0;
}

G:

题意:

又是一道题意题。

给俩字符串,每次洗牌,洗牌规则是交叉交叉交叉,问几次能到达目标串。

解析:

用set来替代Hash判断是否有重复存在。

然后得到这个思路模拟模拟模拟就好了。

具体看代码。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#include <set>
#define LL long long

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    int ca = 1;
    set<string> shuf;
    string aim, str, s1, s2;
    int n;
    while (ncase--)
    {
        cin >> n >> s1 >> s2 >> aim;
        str.resize(2 * n);
        shuf.clear();
        bool found = false;
        int cnt = 0;
        while (!found)
        {
            cnt++;
            for (int i = 0; i < n; i++)
            {
                str[i * 2] = s2[i];
                str[i * 2 + 1] = s1[i];
            }
            for (int i = 0; i < n; i++)
            {
                s1[i] = str[i];
                s2[i] = str[i + n];
            }
            if (str == aim)
            {
                found = true;
                break;
            }
            if (shuf.find(str) == shuf.end())
                shuf.insert(str);
            else
                break;
        }
        printf("%d ", ca++);
        if (found)
            printf("%d\n", cnt);
        else
            printf("-1\n");
    }
    return 0;
}

H:

题意:

倒水问题,给你无限量的水,两容量分别为a, b的杯子,问你能否倒出 c 状态容量的水。

基本操作有:fill1 ...fill2... drop1 ...drop2 ...pour 1 -> 2... pour 2 -> 1...

解析:

按照题意一路dfs暴下去就好了。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 200 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int a, b, c, ans;
string tstring[10000 + 10], astring[1000 + 10];
bool flag, vis[100 + 10][100 + 10];

void dfs(int x, int y, int dep)
{
    if (ans < dep)
        return;
    if (x == c || y == c)
    {
        if (dep < ans)
        {
            ans = dep;
            flag = true;
            for (int i = 0; i < ans; i++)
                astring[i] = tstring[i];
        }
    }
    //fill 1
    if (x < a && !vis[a][y])
    {
        vis[a][y] = true;
        tstring[dep] = "FILL(1)";
        dfs(a, y, dep + 1);
        vis[a][y] = false;
    }
    //fill 2
    if (y < b && !vis[x][b])
    {
        vis[x][b] = true;
        tstring[dep] = "FILL(2)";
        dfs(x, b, dep + 1);
        vis[x][b] = false;
    }
    //drop 1
    if (0 < x && !vis[0][y])
    {
        vis[0][y] = true;
        tstring[dep] = "DROP(1)";
        dfs(0, y, dep + 1);
        vis[0][y] = false;
    }
    //drop2
    if (0 < y && !vis[x][0])
    {
        vis[x][0] = true;
        tstring[dep] = "DROP(2)";
        dfs(x, 0, dep + 1);
        vis[x][0] = false;
    }
    //pour 1 -> 2
    if (0 < x && y < b)
    {
        int t;
        if (x < b - y)
            t = x;
        else
            t = b - y;
        if (!vis[x - t][y + t])
        {
            vis[x - t][y + t] = true;
            tstring[dep] = "POUR(1,2)";
            dfs(x - t, y + t, dep + 1);
            vis[x - t][y + t] = false;
        }
    }
    //pour 2 -> 1
    if (0 < y && x < a)
    {
        int t;
        if (y < a - x)
            t = y;
        else
            t = a - x;
        if (!vis[x + t][y - t])
        {
            vis[x + t][y - t] = true;
            tstring[dep] = "POUR(2,1)";
            dfs(x + t, y - t, dep + 1);
            vis[x + t][y - t] = false;
        }
    }
    return ;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    while (~scanf("%d%d%d", &a, &b, &c))
    {
        memset(vis, false, sizeof(vis));
        vis[0][0] = true;
        flag = false;
        ans = inf;
        dfs(0, 0, 0);
        if (flag)
        {
            printf("%d\n", ans);
            for (int i = 0; i < ans; i++)
            {
                cout << astring[i] << endl;
            }
        }
        else
        {
            printf("impossible\n");
        }
    }
    return 0;
}

I:

题意:

我大fzu的题!鸡冻。

给一张图,图上的#代表一个草,现在你可以hentai的找两个干草点来点燃他们,火势每秒会向上下左右四个方向蔓延。

问最初只点两个草的情况下最快能多快把所有草点燃,若不能输出-1。

解析:

干草点不多,枚举两个#起点来做。

每枚举两个#,就把两个点扔到bfs里面加到队列里,求最短烧完时间。

很显然,要把所有草都点燃,bfs时最后出队列的一定就是时间点了。

然后枚举判断所有#是否都被点燃,若没有,则继续枚举,若有,更新。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 10 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
char g[maxn][maxn];
struct Node
{
    int x, y;
    Node (){}
    Node(int _x, int _y)
    {
        x = _x;
        y = _y;
    }
} p[maxn * maxn];
int step[maxn][maxn];

int bfs(Node a, Node b)
{
    memset(step, -1, sizeof(step));
    int res = 0;
    queue<Node> q;
    q.push(a);
    q.push(b);
    step[a.x][a.y] = 0;
    step[b.x][b.y] = 0;

    while (!q.empty())
    {
        Node now = q.front();
        q.pop();
        int x = now.x;
        int y = now.y;
        res = step[x][y];
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
            if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] == '#' && step[nx][ny] == -1)
            {
                step[nx][ny] = step[x][y] + 1;
                q.push(Node(nx, ny));
            }
        }
    }
    return res;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    int ca = 1;
    scanf("%d", &ncase);
    while (ncase--)
    {
        scanf("%d%d", &n, &m);
        int cnt = 0;
        for (int i = 0; i < n; i++)
        {
            scanf("%s", g[i]);
            for (int j = 0; j < m; j++)
            {
                if (g[i][j] == '#')
                {
                    p[cnt].x = i;
                    p[cnt++].y = j;
                }
            }
        }
        int ans = inf;
        for (int i = 0; i < cnt; i++)
        {
            for (int j = i; j < cnt; j++)
            {
                int t = bfs(p[i], p[j]);
                bool over = true;
                for (int k = 0; k < n; k++)
                {
                    for (int l = 0; l < m; l++)
                    {
                        if (step[k][l] == -1 && g[k][l] == '#')
                        {
                            over = false;
                            break;
                        }
                    }
                    if (!over)
                        break;
                }
                if (over)
                {
                    if (t < ans)
                        ans = t;
                }
            }
        }
        printf("Case %d: ", ca++);
        if (ans == inf)
        {
            printf("-1\n");
        }
        else
        {
            printf("%d\n", ans);
        }
    }
    return 0;
}

J:

题意:

着火密室逃脱play。

给一张图,图上有不止一个着火点F,和上题一样,每秒火苗会往上下左右蔓延。

现在你,J,站在密室中的一个点,问你能否跑出这片火海。当你到达密室边界的时候就算逃脱成功。

解析:

我用了两次bfs,首先第一次先把fire烧到每个点的时间用fireStep保存下来, 相当于先分析火烧的方向与时间。

然后第二次就轮到你,J,来走了,同样是一步一步往外搜,当下个点的没有被火烧到 || 你到达下个点的时间早于火烧到的时间,就把这个点入队。

最后到达边界再+1你就活了!!

先是把出口的 y == m - 1写成n。。。

然后才发现了F可能不止一个地方开始烧。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 1000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
char g[maxn][maxn];
int fireStep[maxn][maxn];
int joesStep[maxn][maxn];
struct Node
{
    int x, y;
    Node(){}
    Node(int _x, int _y)
    {
        x = _x;
        y = _y;
    }
};

void fireBfs()
{
    memset(fireStep, -1, sizeof(fireStep));
    queue<Node> q;
    ///not only one fire
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (g[i][j] == 'F')
            {
                q.push(Node(i, j));
                fireStep[i][j] = 0;
            }
        }
    }
    while (!q.empty())
    {
        Node now = q.front();
        q.pop();
        int x = now.x;
        int y = now.y;
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
            if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] != '#' && fireStep[nx][ny] == -1)
            {
                fireStep[nx][ny] = fireStep[x][y] + 1;
                q.push(Node(nx, ny));
            }
        }
    }
    return;
}

int joesBfs()
{
    memset(joesStep, -1, sizeof(joesStep));
    queue<Node> q;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (g[i][j] == 'J')
            {
                q.push(Node(i, j));
                joesStep[i][j] = 0;
                break;
            }
        }
    }
    while (!q.empty())
    {
        Node now = q.front();
        q.pop();
        int x = now.x;
        int y = now.y;
        if (x == 0 || x == n - 1 || y == 0 || y == m - 1)
        {
            return joesStep[x][y] + 1;
        }
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
            if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] != '#')
            {
                if (joesStep[nx][ny] == -1)
                {
                    if (fireStep[nx][ny] == -1 || joesStep[x][y] + 1 < fireStep[nx][ny])
                    {
                        joesStep[nx][ny] = joesStep[x][y] + 1;
                        q.push(Node(nx, ny));
                    }
                }
            }
        }
    }
    return -1;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
        {
            scanf("%s", g[i]);
        }
        fireBfs();
        int ans = joesBfs();
        if (ans == -1)
        {
            printf("IMPOSSIBLE\n");
        }
        else
        {
            printf("%d\n", ans);
        }
    }
    return 0;
}

K:

题意:

给一个5*5的01迷宫,让你找从左上点(0, 0)到右下点(4, 4)的最短路径,打印。

解析:

这个迷宫这么小,随便搞吧!

结果,打印路径坑死了。。。

这不是和dp的打印路径很像嘛。。。

但是我用了指针。。。可能数据结构写顺手了。。。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 10 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int g[maxn][maxn];
struct Node
{
    int x, y;
    Node* pre;
//    Node(int _x, int _y)
//    {
//        x = _x;
//        y = _y;
//    }
};

void print(Node* now)
{
    if (now -> pre != NULL)
    {
        print(now -> pre);
        printf("(%d, %d)\n", now -> x, now -> y);
    }
}

void bfs(int x, int y)
{
    queue<Node*> q;
    Node* s = new Node;
    g[x][y] = 1;
    s -> x = x;
    s -> y = y;
    s -> pre = NULL;
    q.push(s);
    while (!q.empty())
    {
        Node* now = q.front();
        q.pop();
        int x = now -> x;
        int y = now -> y;
        //cout << now -> x << " " << now -> y << endl;
        if (x == 4 && y == 4)
        {
          //  cout << "ok" << endl;
            printf("(0, 0)\n");
            print(now);
            return;
        }
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
            if (0 <= nx && nx < 5 && 0 <= ny && ny < 5 && g[nx][ny] != 1)
            {
                Node* next = new Node;
                g[nx][ny] = 1;
                next -> x = nx;
                next -> y = ny;
                next -> pre = now;
                q.push(next);
                //cout << q.front() -> x << q.front() -> y << endl;
            }
        }
    }
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            scanf("%d", &g[i][j]);
        }
    }
    bfs(0, 0);
    return 0;
}

L:

题意:

我的入门dfs题,其实是递归。

找八个方向的联通块有多少个。

解析:

枚举@,往下dfs,改@,出联通个数。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
int n, m;
char g[maxn][maxn];

void dfs(int x, int y)
{
    g[x][y] = '.';
    for (int i = 0; i < 8; i++)
    {
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] == '@')
        {
            dfs(nx, ny);
        }
    }
    return;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    while (scanf("%d%d", &n, &m) == 2)
    {
        if (!n && !m)
            break;
        for (int i = 0; i < n; i++)
        {
            scanf("%s", g[i]);
        }
        int ans = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (g[i][j] == '@')
                {
                    dfs(i, j);
                    ans++;
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

M:

题意:

大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。

因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。

但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升(正好装满一瓶)

它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。

聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。

中文题~。

解析:

如果s是奇数,直接NO。

然后就和上面那道倒水题异曲同工了,区别只是这题多了个杯子,并且给定了初始水量。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int a, b, c;
int ans;
bool vis[maxn][maxn][maxn];
int target;

void dfs(int x, int y, int z, int dep)
{
    if ((x == target && y == target) || (x == target && z == target) || (y == target && z == target))
    {
        if (dep < ans)
        {
            ans = dep;
        }
        return;
    }
    //x -> y
    if (0 < x && y < b)
    {
        int t;
        if (x < b - y)
            t = x;
        else
            t = b - y;
        if (!vis[x - t][y + t][z])
        {
            vis[x - t][y + t][z] = true;
            dfs(x - t, y + t, z, dep + 1);
            vis[x - t][y + t][z] = false;
        }
    }
    //y -> x
    if (0 < y && x < a)
    {
        int t;
        if (y < a - x)
            t = y;
        else
            t = a - x;
        if (!vis[x + t][y - t][z])
        {
            vis[x + t][y - t][z] = true;
            dfs(x + t, y - t, z, dep + 1);
            vis[x + t][y - t][z] = false;
        }
    }
    //x -> z
    if (0 < x && z < c)
    {
        int t;
        if (x < c - z)
            t = x;
        else
            t = c - z;
        if (!vis[x - t][y][z + t])
        {
            vis[x - t][y][z + t] = true;
            dfs(x - t, y, z + t, dep + 1);
            vis[x - t][y][z + t] = false;
        }
    }
    //z -> x
    if (0 < z && x < a)
    {
        int t;
        if (z < a - x)
            t = z;
        else
            t = a - x;
        if (!vis[x + t][y][z - t])
        {
            vis[x + t][y][z - t] = true;
            dfs(x + t, y, z - t, dep + 1);
            vis[x + t][y][z - t] = false;
        }
    }
    //y -> z
    if (0 < y && z < c)
    {
        int t;
        if (y < c - z)
            t = y;
        else
            t = c - z;
        if (!vis[x][y - t][z + t])
        {
            vis[x][y - t][z + t] = true;
            dfs(x, y - t, z + t, dep + 1);
            vis[x][y - t][z + t] = false;
        }
    }
    //z -> y
    if (0 < z && y < b)
    {
        int t;
        if (z < b - y)
            t = z;
        else
            t = b - y;
        if (!vis[x][y + t][z - t])
        {
            vis[x][y + t][z - t] = true;
            dfs(x, y + t, z - t, dep + 1);
            vis[x][y + t][z - t] = false;
        }
    }
    return;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    while (~scanf("%d%d%d", &a, &b, &c))
    {
        if (!a && !b && !c)
            break;
        if (a % 2)
        {
            printf("NO\n");
        }
        else
        {
            if (b < c)
            {
                int t = b;
                b = c;
                c = t;
            }
            memset(vis, false, sizeof(vis));
            ans = inf;
            target = a / 2;
            vis[a][0][0] = true;
            dfs(a, 0, 0, 0);
            if (ans == inf)
            {
                printf("NO\n");
            }
            else
            {
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}

N:

题意:

你Y和你的好基友M,现在想见面,图上有好多家kfc @,现在找到一个kcf,使你到那里的距离+ 你基友到那里的距离最短。

解析:

TLE -> CE -> Wa -> MLE...-> Wa......... -> ac

思路是先用bfs找出你到每个kfc的最短距离,然后再用一次bfs找到你基友到每个kfc的最短距离。

然后遍历一次找最小值就行了。

坑点在于,可能有人到达不了其中的kfc,加的话就-1了。

然后MLE的原因是。。。。我刚开始输入了两次m,n。。。。。还有刚开始写的时候脑子有坑,*11 记成*6,查错查了半天。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 200 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
int step[5][maxn][maxn];
char g[maxn][maxn];

struct Node
{
    int x, y;
    Node(int _x, int _y)
    {
        x = _x;
        y = _y;
    }
};

void bfs(int sx, int sy, int key)
{
    queue<Node> q;
    q.push(Node(sx, sy));
    step[key][sx][sy] = 0;

    while (!q.empty())
    {
        Node now = q.front();
        q.pop();
        int x = now.x;
        int y = now.y;
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
            if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] != '#' && step[key][nx][ny] == -1)
            {
                step[key][nx][ny] = step[key][x][y] + 1;
                q.push(Node(nx, ny));
            }
        }
    }
    return;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    while (scanf("%d%d", &n, &m) == 2)
    {

        for (int i = 0; i < n; i++)
        {
            scanf("%s", g[i]);
        }
        int sx1, sy1, sx2, sy2;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (g[i][j] == 'Y')
                {
                    sx1 = i;
                    sy1 = j;
                }
                if (g[i][j] == 'M')
                {
                    sx2 = i;
                    sy2 = j;
                }
            }
        }
        memset(step, -1, sizeof(step));
        bfs(sx1, sy1, 1);
        bfs(sx2, sy2, 2);
        int t = inf;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (g[i][j] == '@'&& step[1][i][j] != -1 && step[2][i][j] != -1)///可能有人到达不了其中的一个kfc
                {
                    if (step[1][i][j] + step[2][i][j] < t)
                        t = step[1][i][j] + step[2][i][j];
                }
            }
        }
        printf("%d\n", t * 11);
    }
    return 0;
}



这些题刷了三天,大白还没有继续刷。

接下来搜索进阶估计要刷好几天,加上大白慢慢来吧。

(●—●)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值