1. 程式人生 > 其它 >搜尋進階

搜尋進階

A - 滑雪

題目連結

思路

搜尋模板題無需多說,注意一下記憶化搜尋和剪枝

程式碼

 

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
typedef pair<int, int> PII;
int n, m, dis[N][N], s[N][N];
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
int dfs(int i, int j)
{
    if (dis[i][j] != 0)
        
return dis[i][j]; dis[i][j]=1; for (int l = 0; l < 4; l++) { int x = i + dx[l]; int y = j + dy[l]; if (x >= 1 && x <= n && y >= 1 && y <= n && s[i][j] > s[x][y]) dis[i][j] = max(dfs(x, y) + 1, dis[i][j]); }
return dis[i][j]; } int main() { cin >> n >> m; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> s[i][j]; int mas = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) mas = max(dfs(i, j), mas); cout
<<mas; return 0; }

 

B - Dungeon Master

題目連結

題意

一個三維的迷宮問題

思路

三維於二維迷宮問題只是多了上下兩個搜尋方向,其餘沒有什麼不同

程式碼

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;

#define maxn 100

struct node
{
    int x, y, z, step;
};

int h, m, n; //高,長和寬
// 6個方向可以走
int dir[6][3] = {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}};
char G[maxn][maxn][maxn];

int OK(int z, int x, int y) //判斷這點是否可以走
{
    if (z >= 0 && z < h && x >= 0 && x < m && y >= 0 && y < n && G[z][x][y] != '#')
        return 1;
    return 0;
}
int DFS(node s, node e)
{
    queue<node> Q;
    Q.push(s);

    while (Q.size())
    {
        s = Q.front();
        Q.pop();

        if (s.x == e.x && s.y == e.y && s.z == e.z)
            return s.step;

        for (int i = 0; i < 6; i++)
        {
            node q = s;
            q.x += dir[i][0];
            q.y += dir[i][1];
            q.z += dir[i][2];
            q.step += 1;

            if (OK(q.z, q.x, q.y) == 1)
            {
                G[q.z][q.x][q.y] = '#';
                Q.push(q);
            }
        }
    }

    return -1;
}

int main()
{
    while (scanf("%d%d%d", &h, &m, &n), h + m + n)
    {
        int i, j, k;
        node s, e;

        for (i = 0; i < h; i++)
            for (j = 0; j < m; j++)
            {
                scanf("%s", G[i][j]);
                for (k = 0; k < n; k++)
                {
                    if (G[i][j][k] == 'S')
                    {
                        s.z = i;
                        s.x = j;
                        s.y = k;
                        s.step = 0;
                    }
                    if (G[i][j][k] == 'E')
                    {
                        e.z = i;
                        e.x = j;
                        e.y = k;
                    }
                }
            }

        int ans = DFS(s, e);

        if (ans != -1)
            printf("Escaped in %d minute(s).\n", ans);
        else
            printf("Trapped!\n");
    }

    return 0;
}

C - 8 Puzzle on Graph

題目連結

題意

給一個 3 x 3 的表格從上到下位置編號為 1~3,4~6,7~9,將1~8 共8個數放入其中,給予一系列的移動規則,如 1 - 2 指編號為1的格子可以於編號為2的格子互換,互換時必須有一個格子為空。問是否能將數字移到對應編號上,如果可以輸出至少移動幾步,不可以輸出 -1

思路

想明白題意花了好長時間,注意題目給的初始狀態是指第幾個數在哪個位置 比如 

    3 9 2 4 5 6 7 8

1 在 編號 3 

2 在 編號 9

 . . .

以此類推

明白了題意接下來就簡單了,只要從空白格子開始廣搜就行了,用字串表示不同狀態同時標記避免重複

程式碼

#include <bits/stdc++.h>
using namespace std;
map<string, int> ma;
int vis[10][10];
vector<int> q[10];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int a, b;
        cin >> a >> b;
        q[a - 1].push_back(b - 1);
        q[b - 1].push_back(a - 1);
    }
    string s = "999999999";
    for (int i = 1; i <= 8; i++)
    {
        int a;
        cin >> a;
        s[a-1] = i + '0';
    }
    queue<string> e;
    e.push(s);
    ma[s] = 0;
    while (!e.empty())
    {
        string s1 = e.front();
        e.pop();
        if (s1 == "123456789")
        {
            cout << ma[s1];
            return 0;
        }
        int k;
        for (int i = 0; i < 9; i++)
            if (s1[i] == '9')
                k = i;
        for (int i = 0; i < q[k].size(); i++)
        {
            string sc = s1;
            swap(sc[k], sc[q[k][i]]);
            if (ma[sc] == 0)
            {
                ma[sc] = ma[s1] + 1;
                e.push(sc);
            }
            
        }
    }
    cout << -1;
    return 0;
}

 

D - Subtree K-th Max

題目連結

題意

n 個數,q 個詢問
接下來一行 n 個數:xi 表示第 i  個點的權值是 xi
接下來 n − 1  行,每行兩個數 a , b ,表示 a  和 b  之間有一條邊
接下來 q  行,每行兩個數 a , b ,問以 a 為根節點的子樹中所有節點權值的第 b大是多少。

思路

從1開始搜尋,每到一個節點記錄以這個節點為根節點的前20大(因為 1<=b<=20,所以記錄20個就夠了)

然後對每個查詢就可以直接輸出

程式碼

#include <bits/stdc++.h>
using namespace std;
const int N = 100233;
int sa[N];
vector<int> q[N];
vector<int> w[N];
bool cmp(int a, int b)
{
    return a > b;
}
void dfs(int t, int p)//t為根結點,p為其父節點
{
    w[t].push_back(sa[t]);
    for (auto x : q[t])
    {
        if (x == p)//避免重複
            continue;
        dfs(x,t);
        for (auto y : w[x])
            w[t].push_back(y);
    }
    sort(w[t].begin(), w[t].end(), cmp);
    if (w[t].size() > 20)
        w[t].resize(20);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> sa[i];
    for (int i = 1; i < n; i++)
    {
        int a, b;
        cin >> a >> b;
        q[a].push_back(b);
        q[b].push_back(a);
    }
    dfs(1, 0);
    for (int i = 1; i <= m; i++)
    {
        int a, k;
        cin >> a >> k;
        cout << w[a][k - 1] << endl;
    }
    return 0;
}