[kuangbin帶你飛]專題1

專題一 簡單搜索

POJ 1321 棋盤問題

在一個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請編程求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案C。

直接DFS,遍歷所有的可能。因爲是一層一層遍歷的,所以只要記錄每一列有沒有出現過就可以

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 1000 + 10;
int n, m;
char map[maxn][maxn];
bool y[maxn];
int sum = 0, tot = 0;

void dfs(int x)
{
    if (x == n) {
        if (sum == m) {
            tot++;
        }
        return;
    }
    dfs(x + 1);
    for (int i = 0; i < n; i++) {
        if (map[x][i] == '#' && !y[i]) {
            y[i] = true;
            sum++;
            dfs(x + 1);
            y[i] = false;
            sum--;
        }
    }
}

int main()
{
    while (1) {
        tot = 0, sum = 0;
        memset(y, 0, sizeof(y));
        scanf("%d%d", &n, &m);
        if (n == -1)
            return 0;
        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
        }
        dfs(0);
        cout << tot << endl;
    }
    return 0;
}

POJ 2251 Dungeon Master

你被困在一個三維地牢,需要找到最快的出路!地牢是由單元立方體組成的,這些立方體可能是石頭,也可能不是石頭。往北、往南、向東、向西、向上或向下移動一個單元需要一分鐘。你不能斜着走,迷宮四周都是堅硬的岩石。
有可能逃跑嗎?如果可以,需要多長時間?

升級版走迷宮,從兩維變成三維,方向從四個方向變成六個方向,直接BFS找最短的路就好

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 42;
int r, n, m;
char map[maxn][maxn][maxn];
int p[maxn][maxn][maxn], tot[maxn][maxn][maxn];
int x1, y1, z1;
int xx[6] = { 1, -1, 0, 0, 0, 0 };
int yy[6] = { 0, 0, 1, -1, 0, 0 };
int zz[6] = { 0, 0, 0, 0, 1, -1 };
struct Point {
    int x, y, z;
};

int bfs(int x, int y, int z)
{
    memset(p, 0, sizeof(p));
    memset(tot, 0, sizeof(tot));
    tot[z][x][y] = 1;
    queue<Point> q;
    q.push((Point){ x, y, z });
    while (!q.empty()) {
        Point k = q.front();
        q.pop();
        for (int i = 0; i < 6; i++) {
            int x0 = k.x + xx[i];
            int y0 = k.y + yy[i];
            int z0 = k.z + zz[i];
            if (x0 >= 0 && x0 < n && y0 >= 0 && y0 < m && z0 >= 0 && z0 < r && map[z0][x0][y0] != '#' && !tot[z0][x0][y0]) {
                tot[z0][x0][y0] = 1;
                p[z0][x0][y0] = p[k.z][k.x][k.y] + 1;
                q.push((Point){ x0, y0, z0 });
                if (map[z0][x0][y0] == 'E') {
                    return p[z0][x0][y0];
                }
            }
        }
    }
    return -1;
}

int main()
{
    while (1) {
        scanf("%d%d%d", &r, &n, &m);
        if (n == 0 && r == 0 && m == 0)
            return 0;
        for (int k = 0; k < r; k++) {
            for (int i = 0; i < n; i++) {
                scanf("%s", map[k][i]);
                for (int j = 0; j < m; j++) {
                    if (map[k][i][j] == 'S') {
                        x1 = i;
                        y1 = j;
                        z1 = k;
                    }
                }
            }
        }
        int l = bfs(x1, y1, z1);
        if (l == -1)
            printf("Trapped!\n");
        else
            printf("Escaped in %d minute(s).\n", l);
    }
    return 0;
}

POJ 3278 Catch That Cow

農場主約翰已被告知一頭逃跑的母牛的位置,他想立即抓住她。它從數軸上的點N開始,牛在同一數軸上的點K開始。農夫約翰有兩種交通方式:步行和心靈運輸。
*步行:FJ可以在一分鐘內從X點移動到X - 1或X + 1點
*心靈移植:FJ可以在一分鐘內從任意X點移動到2×X點。
如果這頭牛根本不知道自己在追它,不動的話,農夫約翰要多久才能把它找回來?

BFS遍歷所有的情況求最優解,不過要考慮FJ可以到達最遠的距離防止TL。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;

const int maxn = 200000 + 100;
int n, m;
bool vis[maxn];
int p[maxn], t;

int bfs(int x)
{
    queue<int> q;
    vis[x] = true;
    q.push(x);
    while (!q.empty()) {
        int k = q.front();
        q.pop();
        t = k + 1;
        if (t >= 0 && t <= 150000 && !vis[t]) {
            vis[t] = true;
            p[t] = p[k] + 1;
            q.push(t);
            if (t == m)
                return p[t];
        }
        t = k - 1;
        if (t >= 0 && t <= 150000 && !vis[t]) {
            vis[t] = true;
            p[t] = p[k] + 1;
            q.push(t);
            if (t == m)
                return p[t];
        }
        t = k * 2;
        if (t >= 0 && t <= 150000 && !vis[t]) {
            vis[t] = true;
            p[t] = p[k] + 1;
            q.push(t);
            if (t == m)
                return p[t];
        }
    }
    return 0;
}

int main()
{
    cin >> n >> m;
    int l = bfs(n);
    cout << l << endl;
    return 0;
}

POJ 3279 Fliptile

農夫約翰知道一頭智力滿足的奶牛是一頭快樂的奶牛,它會產更多的牛奶。他爲奶牛安排了一項腦力活動,讓它們操縱一個M×N的網格(1≤M≤15;1≤N≤15)方片,每方片一面爲黑色,另一面爲白色。
正如人們所猜測的,當一塊白色瓷磚翻轉時,它會變成黑色;當翻轉一個黑色的瓦片時,它會變成白色。當奶牛翻轉瓷磚時,它們會得到獎勵,這樣每塊瓷磚都有一面朝上的白色。然而,奶牛的蹄子相當大,當它們試圖翻轉某個瓦片時,它們也會翻轉所有相鄰的瓦片(與翻轉瓦片共享完整邊緣的瓦片)。由於拋硬幣很累人,奶牛們想把拋硬幣的次數降到最低。
幫助奶牛確定所需翻轉的最少次數,以及要翻轉到最少的位置。如果有多種方法可以用最少的投擲次數來完成任務,那麼當將輸出視爲字符串時,返回字典排序最少的方法。如果任務不可能完成,打印一行“不可能”。

翻瓷磚問題,每次翻一個之後,前後左右四個方向的瓷磚也會被翻過.
先不考慮第一列,在第二列中爲了讓第一列全爲正,所以應該把第一列爲反的瓷磚的下面的進行反轉,以此類推,直到最後一列,若最後最後一列全爲正則合理,否則不合理,所以只要第一列確定了後面的結果就確定了,所以只要把第一列的所以情況枚舉出來就可以。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int maxn = 100;
int map[maxn][maxn], p[maxn], q[maxn][maxn], t[maxn][maxn], lll[maxn][maxn];
int n, m;

void Put(int x, int y)
{
    int xx[5] = { 0, 0, 0, 1, -1 };
    int yy[5] = { 1, -1, 0, 0, 0 };
    for (int i = 0; i < 5; i++) {
        int x0 = x + xx[i];
        int y0 = y + yy[i];
        if (x0 >= 0 && y0 >= 0 && x0 < n && y0 < m) {
            q[x0][y0] ^= 1;
        }
    }
}

int work()
{
    int sum = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            q[i][j] = map[i][j];
        }
    }
    for (int i = 0; i < m; i++) {
        if (p[i]) {
            Put(0, i);
            sum++;
            t[0][i] = 1;
        }
    }
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (q[i - 1][j]) {
                Put(i, j);
                sum++;
                t[i][j] = 1;
            }
        }
    }
    for (int i = 0; i < m; i++) {
        if (q[n - 1][i])
            return -1;
    }
    return sum;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &map[i][j]);
        }
    }
    int flag = 0, maxx = 1e9;
    for (int i = 0; i < (1 << m); i++) {
        memset(p, 0, sizeof(p));
        memset(t, 0, sizeof(t));
        for (int j = 0; j < m; j++) {
            if ((1 << j) & i)
                p[j] = 1;
        }
        int l = work();
        if (l != -1) {
            flag = 1;
            if (l < maxx) {
                maxx = l;
                for (int i = 0; i < n; i++) {
                    for (int j = 0; j < m; j++) {
                        lll[i][j] = t[i][j];
                    }
                }
            }
        }
    }
    if (!flag) {
        cout << "IMPOSSIBLE" << endl;
    } else {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                printf("%d ", lll[i][j]);
            }
            cout << endl;
        }
    }
    return 0;
}

POJ 1426 Find The Multiple

給定一個正整數n,編寫一個程序找出一個n的非零倍數m,其十進制表示僅包含數字0和1。您可以假設n不大於200,並且對應的m包含不超過100位小數。

直接暴力枚舉所有的0,1情況從1開始每次×10,或者×10+1,得到的數對n取模就可以

#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
#define ll long long

void bfs(int n)
{
    queue<ll> q;
    q.push(1);
    while (!q.empty()) {
        ll k = q.front();
        if (k % n == 0) {
            cout << k << endl;
            return;
        }
        q.pop();
        q.push(k * 10);
        q.push(k * 10 + 1);
    }
    return;
}

int main()
{
    int n;
    while (scanf("%d", &n), n) {
        bfs(n);
    }
    return 0;
}

POJ 3126 Prime Path

-事實上,我有。你看,有一場編程比賽正在進行……幫助總理在任意兩個給定的四位素數之間找到最便宜的素數路徑!當然,第一個數字必須是非零的。在上面的例子中有一個解。
1033
1733
3733
3739
3779
8779
8179
這個解決方案的成本是6英鎊。注意,第2步中粘貼的數字1不能在最後一步中重用——必須購買一個新的1。

直接暴力枚舉每一位的情況,如果是素數就繼續遍歷直到找到另一個素數。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;

int T, sum;
int aa, bb;
bool vis[10000];
struct node {
    int x, cnt;
};

bool pd(int x)
{
    if (x == 0 || x == 1)
        return false;
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0)
            return false;
    }
    return true;
}

int bfs(int x, int cnt)
{
    queue<node> q;
    q.push((node){ x, cnt });
    vis[x] = true;
    if (x == bb) {
        return 0;
    }
    while (!q.empty()) {
        node k = q.front();
        q.pop();
        for (int i = 0; i <= 9; i++) {
            int a = k.x % 10;
            int b = (k.x / 10) % 10;
            int c = (k.x / 100) % 10;
            int d = (k.x / 1000) % 10;
            int t1 = (((((i * 10) + c) * 10) + b) * 10) + a;
            if (pd(t1) && !vis[t1] && i != 0) {
                vis[t1] = true;
                q.push((node){ t1, k.cnt + 1 });
                if (t1 == bb) {
                    return k.cnt + 1;
                }
            }
            t1 = (((((d * 10) + i) * 10) + b) * 10) + a;
            if (pd(t1) && !vis[t1]) {
                vis[t1] = true;
                q.push((node){ t1, k.cnt + 1 });
                if (t1 == bb) {
                    return k.cnt + 1;
                }
            }
            t1 = (((((d * 10) + c) * 10) + i) * 10) + a;
            if (pd(t1) && !vis[t1]) {
                vis[t1] = true;
                q.push((node){ t1, k.cnt + 1 });
                if (t1 == bb) {
                    return k.cnt + 1;
                }
            }
            t1 = (((((d * 10) + c) * 10) + b) * 10) + i;
            if (pd(t1) && !vis[t1]) {
                vis[t1] = true;
                q.push((node){ t1, k.cnt + 1 });
                if (t1 == bb) {
                    return k.cnt + 1;
                }
            }
        }
    }
    return -1;
}

int main()
{
    cin >> T;
    while (T--) {
        memset(vis, 0, sizeof(vis));
        scanf("%d%d", &aa, &bb);
        int l = bfs(aa, 0);
        if (l == -1)
            cout << "Impossible" << endl;
        else
            cout << l << endl;
    }
    return 0;
}

POJ 3087 Shuffle’m Up

撲克玩家在牌桌上最常見的消遣就是洗牌。洗牌籌碼由兩堆撲克籌碼開始,分別是S1和S2,每堆都包含C個籌碼。每個堆棧可以包含幾種不同顏色的芯片。
實際的shuffle操作是將S1的芯片與S2的芯片交叉,如下圖所示,C = 5:
avatar
單個結果堆棧S12包含2 * C芯片。S12的底端芯片是S2的底端芯片。在那個芯片的上面,是S1的最下面的芯片。交叉過程繼續從S2的底部取出第二個芯片並將其放置在S12上,然後從S1的底部取出第二個芯片,以此類推,直到S1的頂部芯片被放置在S12上。
洗牌操作後,將S12分成兩個新的棧,從S12中取出最底層的C片形成一個新的S1,從S12中取出頂層的C片形成一個新的S2。然後可以重複洗牌操作以形成一個新的S12。
對於這個問題,您將編寫一個程序來確定一個特定的結果堆棧S12是否可以通過將兩個堆棧打亂若干次來形成。

直接遍歷所有洗牌後的狀態即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <string>
using namespace std;
const int maxn = 2000 + 100;
int T;
int n, minn, sum;
string a, b, c;
map<string, bool> q;

void dfs()
{
    string t;
    for (int i = 0; i < n; i++) {
        t += b[i];
        t += a[i];
    }
    if (t == c) {
        minn = min(sum, minn);
        return;
    }
    if (!q[t]) {
        q[t] = true;
        a = "";
        b = "";
        for (int i = 0; i < n; i++) {
            a += t[i];
        }
        for (int i = 0; i < n; i++) {
            b += t[i + n];
        }
        sum++;
        dfs();
    }
}

int main()
{
    cin >> T;
    for (int lll = 1; lll <= T; lll++) {
        minn = 1e9;
        cin >> n;
        cin >> a >> b >> c;
        q.clear();
        sum = 1;
        dfs();
        if (minn == 1e9)
            printf("%d -1\n", lll);
        else
            printf("%d %d\n", lll, minn);
    }
    return 0;
}

POJ 3414 Pots

你有兩個壺,分別有A和B升的體積。可以執行以下操作:

  1. FILL(i) 從水龍頭往i(1≤i≤2)罐內灌滿;
  2. DROP(i) 把鍋裏的水倒進排水溝裏;
  3. POUR(i,j) 從鍋i倒到鍋j;在這個操作之後,要麼鍋j滿了(可能鍋i中還剩下一些水),要麼鍋i是空的(它的所有內容都被移到了鍋j中)。

編寫一個程序,找出這些操作中最短的可能順序,使其中一個罐子剛好能產生C公升的水。

BFS 枚舉每種變化,記錄最短的路徑,其實不是很難就是寫起來比較複雜而已

#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;

int a, b, c, xx, yy;
struct E {
    int x, y, cnt;
};
struct p {
    int x, y, o;
} e[1000][1000];
bool vis[1000][1000];
int bfs()
{
    queue<E> q;
    q.push((E){ 0, 0, 0 });
    vis[0][0] = true;
    while (!q.empty()) {
        E k = q.front();
        if (k.x == c || k.y == c) {
            xx = k.x, yy = k.y;
            return k.cnt;
        }

        q.pop();
        int x, y;
        x = 0;
        y = k.y;
        if (!vis[x][y]) {
            e[x][y] = (p){ k.x, k.y, 1 };
            vis[x][y] = true;
            q.push((E){ x, y, k.cnt + 1 });
        }
        x = k.x;
        y = 0;
        if (!vis[x][y]) {
            e[x][y] = (p){ k.x, k.y, 2 };
            vis[x][y] = true;
            q.push((E){ x, y, k.cnt + 1 });
        }
        x = a;
        y = k.y;
        if (!vis[x][y]) {
            e[x][y] = (p){ k.x, k.y, 3 };
            vis[x][y] = true;
            q.push((E){ x, y, k.cnt + 1 });
        }
        x = k.x;
        y = b;
        if (!vis[x][y]) {
            e[x][y] = (p){ k.x, k.y, 4 };
            vis[x][y] = true;
            q.push((E){ x, y, k.cnt + 1 });
        }
        if (k.x > b - k.y) {
            x = k.x - (b - k.y);
            y = b;
        } else {
            x = 0;
            y = k.y + k.x;
        }
        if (!vis[x][y]) {
            e[x][y] = (p){ k.x, k.y, 5 };
            vis[x][y] = true;
            q.push((E){ x, y, k.cnt + 1 });
        }
        if (k.y > a - k.x) {
            x = a;
            y = k.y - (a - k.x);
        } else {
            x = k.y + k.x;
            y = 0;
        }
        if (!vis[x][y]) {
            e[x][y] = (p){ k.x, k.y, 6 };
            vis[x][y] = true;
            q.push((E){ x, y, k.cnt + 1 });
        }
    }
    return -1;
}

void print(int x, int y)
{
    if (x == 0 && y == 0)
        return;
    print(e[x][y].x, e[x][y].y);
    switch (e[x][y].o) {
    case 1:
        cout << "DROP(1)";
        break;
    case 2:
        cout << "DROP(2)";
        break;
    case 3:
        cout << "FILL(1)";
        break;
    case 4:
        cout << "FILL(2)";
        break;
    case 5:
        cout << "POUR(1,2)";
        break;
    case 6:
        cout << "POUR(2,1)";
        break;
    default:
        break;
    }
    cout << endl;
}

int main()
{
    cin >> a >> b >> c;
    int l = bfs();
    if (l == -1)
        cout << "impossible" << endl;
    else {
        cout << l << endl;
        print(xx, yy);
    }
}

FZU 2150 Fire Game

胖哥和迷宮在一個N*M的棋盤(N行,M列)上玩一種特殊的(hentai)遊戲。開始的時候,每個格子都是草或者是空的然後他們開始點燃所有的草。首先,他們選擇由草和火組成的兩個網格。我們都知道,火可以在草地上蔓延。如果網格(x, y)在t時刻觸發,則與此網格相鄰的網格將在t+1時刻觸發,t+1表示網格(x+1, y) (x, y+1) (x, y+1) (x, y+1) (x, y) (x, y+1) (x, y) (x, y) (x, y)這個過程結束時,沒有新的網格得到火。如果所有由草組成的格子都被燒壞了,胖哥和迷宮就會站在格子中間,玩一個更特別的(hentai)遊戲。(也許是在最後一個問題中解密的OOXX遊戲,誰知道呢。)
你可以假設木板上的草永遠不會燒完,空格子永遠不會着火。
注意,他們選擇的兩個網格可以是相同的。

點火問題,選擇兩個點開始BFS,求最短的時間。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 200 + 10;
int T, n, m;
char map[maxn][maxn];
int vis[maxn][maxn];
int xx[4] = { 1, -1, 0, 0 };
int yy[4] = { 0, 0, 1, -1 };
int x1, x2, y1, y2;
struct Point {
    int x, y;
} e[maxn];
int tot = 0, cnt;
int dfs(int a, int b)
{
    cnt = 1;
    queue<Point> q;
    q.push((Point){ e[a].x, e[a].y });
    q.push((Point){ e[b].x, e[b].y });
    vis[e[a].x][e[a].y] = 1;
    vis[e[b].x][e[b].y] = 1;
    while (!q.empty()) {
        Point k = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int x0 = k.x + xx[i];
            int y0 = k.y + yy[i];
            if (x0 >= 0 && x0 < n && y0 >= 0 && y0 < m && map[x0][y0] == '#' && !vis[x0][y0]) {
                vis[x0][y0] = vis[k.x][k.y] + 1;
                q.push((Point){ x0, y0 });
                cnt = max(cnt, vis[x0][y0]);
            }
        }
    }
    return cnt;
}
int main()
{
    cin >> T;
    for (int ll = 1; ll <= T; ll++) {
        tot = 0;
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
            for (int j = 0; j < m; j++) {
                if (map[i][j] == '#') {
                    e[++tot].x = i;
                    e[tot].y = j;
                }
            }
        }
        int sum = 1e9;
        for (int i = 1; i <= tot; i++) {
            for (int j = i; j <= tot; j++) {
                memset(vis, 0, sizeof(vis));
                int lll = dfs(i, j);
                int flag = 0;
                for (int k = 0; k < n; k++) {
                    for (int l = 0; l < m; l++) {
                        if (map[k][l] == '#' && !vis[k][l]) {
                            flag = 1;
                            break;
                        }
                        if (flag)
                            break;
                    }
                }
                if (!flag)
                    sum = min(sum, lll - 1);
            }
        }
        if (sum == 1e9)
            printf("Case %d: -1\n", ll);
        else
            printf("Case %d: %d\n", ll, sum);
    }
    return 0;
}

UVA 11624 Fire!

喬在迷宮裏工作。不幸的是,迷宮的部分區域有着火了,迷宮的主人忘記生火了逃跑計劃。幫助喬逃離迷宮。給定喬在迷宮中的位置和迷宮的哪個方塊是着火了,你必須先確定喬是否能逃出迷宮火到達了他的身邊,他能以多快的速度做到這一點。喬和火每分鐘移動一個正方形,垂直或水平(不是對角)。大火向四面八方蔓延從每一個着火的廣場。喬可以從任何一個迷宮中出迷宮邊緣的正方形。既不是喬也不是火可以進入一個被牆佔據的廣場。

兩次遍歷,第一次求出火蔓延到各個點的時間,第二次在着火的約束下求走出迷宮的最短時間。注意着火點不止有有一個。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 1000 + 10;
int n, m, T, ttt;
int x1, y1, x2[maxn], y2[maxn], vis[maxn][maxn];
char map[maxn][maxn];
int xx[4] = { 1, -1, 0, 0 };
int yy[4] = { 0, 0, 1, -1 };
struct Point {
    int x, y;
};
bool tot[maxn][maxn];
void bfs()
{

    memset(tot, 0, sizeof(tot));
    queue<Point> q;
    for (int i = 1; i <= ttt; i++) {
        q.push((Point){ x2[i], y2[i] });
        tot[x2[i]][y2[i]] = 1;
        vis[x2[i]][y2[i]] = 1;
    }
    while (!q.empty()) {
        Point k = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int x0 = k.x + xx[i];
            int y0 = k.y + yy[i];
            if (x0 >= 0 && x0 < n && y0 >= 0 && y0 < m && map[x0][y0] != '#' && !tot[x0][y0]) {
                tot[x0][y0] = 1;
                vis[x0][y0] = vis[k.x][k.y] + 1;
                q.push((Point){ x0, y0 });
            }
        }
    }
}
int p[maxn][maxn];
int bfs2(int x, int y)
{

    memset(p, 0, sizeof(p));
    tot[x][y] = 1;
    memset(tot, 0, sizeof(tot));
    p[x][y] = 1;
    queue<Point> q;
    q.push((Point){ x, y });
    if (x == 0 || y == 0 || x == n - 1 || y == m - 1)
        return 1;
    while (!q.empty()) {
        Point k = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int x0 = k.x + xx[i];
            int y0 = k.y + yy[i];
            if (x0 >= 0 && x0 < n && y0 >= 0 && y0 < m && map[x0][y0] != '#' && !tot[x0][y0] && (p[k.x][k.y] + 1 < vis[x0][y0] || !vis[x0][y0])) {
                tot[x0][y0] = 1;
                p[x0][y0] = p[k.x][k.y] + 1;
                q.push((Point){ x0, y0 });
                if (x0 == 0 || y0 == 0 || x0 == n - 1 || y0 == m - 1)
                    return p[x0][y0];
            }
        }
    }
    return -1;
}

int main()
{
    scanf("%d", &T);
    while (T--) {
        memset(vis, 0, sizeof(vis));
        scanf("%d%d", &n, &m);
        ttt = 0;
        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
            for (int j = 0; j < m; j++) {
                if (map[i][j] == 'J') {
                    x1 = i, y1 = j;
                }
                if (map[i][j] == 'F') {
                    x2[++ttt] = i, y2[ttt] = j;
                }
            }
        }
        bfs();
        int t = bfs2(x1, y1);
        if (t == -1)
            cout << "IMPOSSIBLE" << endl;
        else
            cout << t << endl;
    }
    return 0;
}

POJ 3984 迷宮問題

定義一個二維數組:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一個迷宮,其中的1表示牆壁,0表示可以走的路,只能橫着走或豎着走,不能斜着走,要求編程序找出從左上角到右下角的最短路線。

BFS求最短路,並記錄最短路的路徑

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 10;
int map[maxn][maxn], tot = 1;
int vis[maxn][maxn], p[maxn][maxn], x[maxn], y[maxn];
int xx[4] = { 1, 0, 0, -1 };
int yy[4] = { 0, -1, 1, 0 };
struct Point {
    int x, y;
};
void bfs(int a, int b)
{
    queue<Point> q;
    q.push((Point){ a, b });
    while (!q.empty()) {
        Point k = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int x0 = k.x + xx[i];
            int y0 = k.y + yy[i];
            if (x0 >= 0 && x0 < 5 && y0 >= 0 && y0 < 5 && map[x0][y0] == 0 && !vis[x0][y0]) {
                vis[x0][y0] = 1;
                p[x0][y0] = 3 - i;
                q.push((Point){ x0, y0 });
                if (x0 == 4 && y0 == 4)
                    return;
            }
        }
    }
}
void dfs(int ax, int ay)
{
    if (ax == 0 && ay == 0)
        return;
    x[++tot] = ax + xx[p[ax][ay]];
    y[tot] = ay + yy[p[ax][ay]];

    dfs(x[tot], y[tot]);
}
int main()
{
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            scanf("%d", &map[i][j]);
        }
    }
    bfs(0, 0);
    dfs(4, 4);
    x[1] = 4, y[1] = 4;
    for (int i = tot; i > 0; i--) {
        printf("(%d, %d)\n", x[i], y[i]);
    }
    return 0;
}

HDU 1241 Oil Deposits

地質urvcomp地質勘測公司負責探測地下油層。GeoSurvComp每次處理一個大的矩形區域,並創建一個網格,將土地劃分爲許多方形地塊。然後用傳感設備分別分析每個地塊,以確定該地塊是否含有石油。一塊含有石油的土地叫做口袋。如果兩個儲層相鄰,則它們屬於同一油層的一部分。石油儲量可以相當大,可能包含許多口袋。你的工作是確定有多少不同的石油蘊藏在一個網格。

尋找地圖中有多少聯通塊,直接遍歷把遍歷過的點改爲*即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 100 + 10;
int n, m, sum;
char map[maxn][maxn];
bool vis[maxn][maxn];
int xx[8] = { 1, -1, 0, 0, 1, 1, -1, -1 };
int yy[8] = { 0, 0, 1, -1, 1, -1, 1, -1 };
void dfs(int x, int y)
{
    map[x][y] = '*';
    for (int i = 0; i < 8; i++) {
        int x0 = x + xx[i];
        int y0 = y + yy[i];
        if (x >= 0 && x < n && y >= 0 && y < m && map[x0][y0] == '@') {
            dfs(x0, y0);
        }
    }
}
int main()
{
    while (1) {
        memset(vis, 0, sizeof(vis));
        scanf("%d%d", &n, &m);
        sum = 0;
        if (n == 0)
            return 0;
        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (map[i][j] == '@') {
                    dfs(i, j);
                    sum++;
                }
            }
        }
        printf("%d\n", sum);
    }
    return 0;
}

HDU 1495 非常可樂

大家一定覺的運動以後喝可樂是一件很愜意的事情,但是seeyou卻不這麼認爲。因爲每次當seeyou買了可樂以後,阿牛就要求和seeyou一起分享這一瓶可樂,而且一定要喝的和seeyou一樣多。但seeyou的手中只有兩個杯子,它們的容量分別是N 毫升和M 毫升 可樂的體積爲S (S<101)毫升 (正好裝滿一瓶) ,它們三個之間可以相互倒可樂 (都是沒有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聰明的ACMER你們說他們能平分嗎?如果能請輸出倒可樂的最少的次數,如果不能輸出"NO"。

簡單的模擬暴力,但在條件處理是要注意,容易出現錯誤

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;

const int maxn = 200;
int b[3];
bool vis[maxn][maxn][maxn];

struct E {
    int val[3], cnt;
};

bool pd(int tt[3])
{
    int t = b[0] / 2;
    if ((tt[0] == t && tt[1] == t) || (tt[2] == t && tt[1] == t) || (tt[0] == t && tt[2] == t))
        return true;
    return false;
}

int bfs()
{
    E aa;
    aa.val[0] = b[0], aa.val[1] = 0, aa.val[2] = 0;
    aa.cnt = 0;
    queue<E> q;
    q.push(aa);
    memset(vis, 0, sizeof(vis));
    vis[b[0]][0][0] = true;
    while (!q.empty()) {
        E k = q.front();
        q.pop();
        for (int i = 0; i < 3; i++) {
            if (k.val[i])
                for (int j = 0; j < 3; j++) {
                    if (i == j)
                        continue;
                    E pp = k;
                    pp.cnt++;
                    if (k.val[i] > b[j] - k.val[j]) {
                        pp.val[i] -= b[j] - k.val[j];
                        pp.val[j] = b[j];
                    } else {
                        pp.val[i] = 0;
                        pp.val[j] += k.val[i];
                    }
                    if (!vis[pp.val[0]][pp.val[1]][pp.val[2]]) {
                        vis[pp.val[0]][pp.val[1]][pp.val[2]] = true;
                        q.push(pp);
                        if (pd(pp.val)) {
                            return pp.cnt;
                        }
                    }
                }
        }
    }
    return -1;
}

int main()
{
    while (scanf("%d%d%d", &b[0], &b[1], &b[2]), b[1] + b[0] + b[2]) {
        if (b[0] % 2 == 1)
            printf("NO\n");
        else {
            int l = bfs();
            if (l == -1)
                printf("NO\n");
            else
                printf("%d\n", l);
        }
    }
    return 0;
}

HDU 2612 Find a way

ass在杭州學習了一年,終於抵達家鄉寧波。離開寧波一年,依芬飛有很多人要見面。尤其是好朋友梅爾斯基。
一芬飛的家在鄉下,但奔馳的家在市中心。於是易芬飛和奔馳約好在肯德基見面。寧波有很多肯德基,他們想選擇一個讓總時間最小的。
現在給你一張寧波地圖,一芬飛和奔馳都可以上下左右移動到相鄰的路上,只需要11分鐘。

兩次BFS,求出每個人到每個KFC的最短距離。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;

const int maxn = 200 + 10;
int n, m, sum;
char map[maxn][maxn];
int vis[maxn][maxn], vis2[maxn][maxn];
int xx[4] = { 1, -1, 0, 0 };
int yy[4] = { 0, 0, 1, -1 };
int x1, x2, y1, y2;
struct Point {
    int x, y;
};

void bfs(int x, int y, int t)
{
    bool tot[maxn][maxn];
    int ttt = 0;
    memset(tot, 0, sizeof(tot));
    tot[x][y] = 1;
    queue<Point> q;
    q.push((Point){ x, y });
    while (!q.empty()) {
        Point k = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int x0 = k.x + xx[i];
            int y0 = k.y + yy[i];
            if (x0 < 0 || x0 >= n || y0 < 0 || y0 >= m || map[x0][y0] == '#' || tot[x0][y0])
                continue;
            if (t)
                vis[x0][y0] = vis[k.x][k.y] + 1;
            else
                vis2[x0][y0] = vis2[k.x][k.y] + 1;
            tot[x0][y0] = 1;
            q.push((Point){ x0, y0 });
        }
    }
}

int main()
{
    while (~scanf("%d%d", &n, &m)) {
        sum = 0;
        memset(vis, 0, sizeof(vis));
        memset(vis2, 0, sizeof(vis2));
        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
            for (int j = 0; j < m; j++) {
                if (map[i][j] == 'Y')
                    x1 = i, y1 = j;
                if (map[i][j] == 'M')
                    x2 = i, y2 = j;
                if (map[i][j] == '@')
                    sum++;
            }
        }
        bfs(x1, y1, 0);
        bfs(x2, y2, 1);
        int minn = 1e9;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (map[i][j] == '@' && vis[i][j] && vis2[i][j]) {
                    minn = min(minn, (vis[i][j] + vis2[i][j]) * 11);
                }
            }
        }
        printf("%d\n", minn);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章