專題一 簡單搜索
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:
單個結果堆棧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升的體積。可以執行以下操作:
- FILL(i) 從水龍頭往i(1≤i≤2)罐內灌滿;
- DROP(i) 把鍋裏的水倒進排水溝裏;
- 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;
}