搜索問題
DFS :
一般適用於 枚舉每一條路徑的情況,比如八皇后問題,或者棋盤問題,但是有時候枚舉出所有路徑沒超時,所以我們可能需要去加入剪枝,剪掉顯然不能滿足條件的情況
BFS:
一般適用於求最短路徑,或者說給出一張圖,然後有多個地方要到達,我們可以直接BFS一遍,將每個能到達的點表上步數,這樣我們搜索一遍,就能知道到達每個地方的最短路徑了,這樣面對給出一張圖,然後很多組詢問就不會超時
A_POJ1321_棋盤問題
思路
因爲給出的棋盤 不是全都可以擺放的
只有符號爲’#’的區域 纔是可以擺放的 而且擺放的個數 也是由數據給出的 ,並不是一定的
所以要注意一下
其實還是一層一層 往下搜
當擺放個數達到要求是 就更新答案
搜索方式:DFS
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1);
const double E = exp(1);
const double eps = 1e-30;
const int INF = 0x3f3f3f3f;
const int maxn = 5e4 + 5;
const int MOD = 1e9 + 7;
string G[10];
int ans;
int n, k, m;
int v[10];
void dfs(int cur)
{
if (m == k)
{
ans++;
return;
}
if (cur >= n)
return;
for (int i = 0; i < n; i++)
{
if (G[cur][i] == '#' && v[i] == 0)
{
v[i] = 1;
m++;
dfs(cur + 1);
m--;
v[i] = 0;
}
}
dfs(cur + 1);
}
void init()
{
CLR(v);
ans = 0;
}
int main()
{
while (scanf("%d%d", &n, &k))
{
if (n == -1 && k == -1)
break;
for (int i = 0; i < n; i++)
cin >> G[i];
init();
m = 0;
dfs(0);
cout << ans << endl;
}
}
B - Dungeon Master POJ - 2251
題意
給出一個三維地圖 求從s點 到達 E點 最少需要花費的時間 如果到達不了 就輸出 “Trapped!”
思路
其實就是求最短路徑問題,那麼自然就是用BFS
就是經典的迷宮問題,方向從四個變爲六個罷了
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = 3e1 + 5;
const int MOD = 1e9 + 7;
int G[maxn][maxn][maxn];
int v[maxn][maxn][maxn];
int sx, sy, sz, ex, ey, ez;
int Move[6][3]
{
1, 0, 0,
-1, 0, 0,
0, 1, 0,
0,-1, 0,
0, 0, 1,
0, 0,-1,
};
struct node
{
int x, y, z;
int step;
};
int ans;
int c, n, m;
bool ok(int x, int y, int z)
{
if (x < 0 || x >= c || y < 0 || y >= n || z < 0 || z >= m || G[x][y][z] || v[x][y][z])
return false;
return true;
}
void bfs()
{
node tmp;
tmp.x = sx;
tmp.y = sy;
tmp.z = sz;
tmp.step = 0;
queue <node> q;
q.push(tmp);
v[sx][sy][sz] = 1;
while (!q.empty())
{
node u = q.front(), V;
q.pop();
if (u.x == ex && u.y == ey && u.z == ez)
{
ans = u.step;
return;
}
for (int i = 0; i < 6; i++)
{
V.x = u.x + Move[i][0];
V.y = u.y + Move[i][1];
V.z = u.z + Move[i][2];
if (ok(V.x, V.y, V.z))
{
V.step = u.step + 1;
q.push(V);
v[V.x][V.y][V.z] = 1;
}
}
}
}
int main()
{
while (scanf("%d%d%d", &c, &n, &m) && (c || n || m))
{
CLR(G, 0);
CLR(v, 0);
string s;
for (int i = 0; i < c; i++)
{
for (int j = 0; j < n; j++)
{
cin >> s;
for (int k = 0; k < m; k++)
{
if (s[k] == 'S')
{
sx = i;
sy = j;
sz = k;
G[i][j][k] = 0;
}
else if (s[k] == 'E')
{
ex = i;
ey = j;
ez = k;
G[i][j][k] = 0;
}
else if (s[k] == '.')
G[i][j][k] = 0;
else if (s[k] == '#')
G[i][j][k] = 1;
}
}
}
ans = -1;
bfs();
if (ans == -1)
printf("Trapped!\n");
else
printf("Escaped in %d minute(s).\n", ans);
}
}
C - Catch That Cow POJ - 3278
題意
給出一個數 每一步有三種操作
x - 1 x + 1 x * 2
然後求得 變成目標數 最少需要幾步操作
最少 那麼自然也是想到BFS 和迷宮問題的區別 也就是在於 這個是對數操作吧
然後 標記一下 訪問過的數就 可以 防止爆
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 5;
const int MOD = 1e9 + 7;
int n, k;
int ans;
int v[maxn];
struct node
{
int v, step;
};
bool ok(int x)
{
if (x < 0 || x > maxn)
return false;
return true;
}
void bfs()
{
CLR(v, 0);
queue <node> q;
node tmp;
tmp.v = n;
tmp.step = 0;
q.push(tmp);
v[n] = 1;
while (!q.empty())
{
node u = q.front(), V;
q.pop();
if (u.v == k)
{
ans = u.step;
return;
}
V.step = u.step + 1;
V.v = u.v + 1;
if (ok(V.v) && v[V.v] == 0)
{
q.push(V);
v[V.v] = 1;
}
V.v = u.v - 1;
if (ok(V.v) && v[V.v] == 0)
{
q.push(V);
v[V.v] = 1;
}
V.v = u.v * 2;
if (ok(V.v) && v[V.v] == 0)
{
q.push(V);
v[V.v] = 1;
}
}
}
int main()
{
scanf("%d%d", &n, &k);
ans = INF;
bfs();
cout << ans << endl;
}
D - Fliptile POJ - 3279
題意
給出一個 01 矩陣
奶牛每次可以翻轉其中一個數字 但是它周圍的四個數字(如果存在的話) 也會跟着翻轉
求最少的翻轉次數 使得 所有的數字都變成0
思路
其實說是搜索 不如說是枚舉更好吧
因爲對於這種問題,,如果第一行的翻轉數確定了,那麼後面的翻轉數也是能夠確定的
因爲第一行的翻轉數確定了,那麼第一行在經過第一行翻轉之後 它的狀態是0還是1 也是確定的
那麼我們如果需要改變它的狀態,只能夠經過第二行的翻轉來達到,也就是說,第二行的翻轉數也確定了
那麼迭代下去 我們發現,最後一行的翻轉狀態是沒有辦法 再經過下一行的翻轉來改變的
那麼最後一行的翻轉狀態就可以成爲我們來判定這種翻轉方式是不是可行的 如果是可行的 並且翻轉次數是小於之前的答案的話 ,那麼我們就更新 最後輸出
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back
#define bug puts("***bug***");
//#define gets gets_s
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <string, int> psi;
typedef pair <string, string> pss;
typedef pair <double, int> pdi;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 10;
const int MOD = 1e9 + 7;
int G[16][16];
int out[16][16];
int tmp[16][16];
int mmap[16][16];
int ans;
int n, m;
int Move[5][2] =
{
-1, 0,
1, 0,
0,-1,
0, 1,
0, 0,
};
bool ok(int x, int y)
{
if (x < 0 || x >= n || y < 0 || y >= m)
return false;
return true;
}
void solve(int x)
{
int tot = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
tmp[i][j] = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
mmap[i][j] = G[i][j];
for (int i = 0; i < m; i++)
{
tmp[0][i] = x & 1;
if (x & 1)
{
tot++;
for (int j = 0; j < 5; j++)
{
int x = Move[j][0] + 0;
int y = Move[j][1] + i;
if (ok(x, y))
mmap[x][y] ++;
}
}
x >>= 1;
}
for (int i = 1; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (mmap[i - 1][j] & 1)
{
tmp[i][j]++;
tot++;
for (int k = 0; k < 5; k++)
{
int x = i + Move[k][0];
int y = j + Move[k][1];
if (ok(x, y))
mmap[x][y]++;
}
}
}
}
for (int i = 0; i < m; i++)
{
if (mmap[n - 1][i] & 1)
return;
}
if (tot < ans)
{
ans = tot;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
out[i][j] = tmp[i][j];
}
}
void init()
{
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
out[i][j] = 0;
}
int main()
{
while (~scanf("%d%d", &n, &m))
{
init();
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
scanf("%d", &G[i][j]);
int len = (1 << m);
ans = INF;
for (int i = 0; i < len; i++)
solve(i);
if (ans == INF)
{
puts("IMPOSSIBLE");
continue;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (j)
printf(" ");
printf("%d", out[i][j]);
}
printf("\n");
}
}
}
E - Find The Multiple POJ - 1426
題意
構造一個只有0和1構成的十進制數字 使得這個數字能夠整除給出的N
思路
其實我們可以想到
可以枚舉下一位
因爲最高位肯定是1
那麼下一位便可以是0 或者 1
這樣就分出兩種狀態
就用BFS 隊列保存就可以了
而且這一題的數據 好像沒有那麼強,用ll就可以過了。。 雖然說題目說構造的數不超過100 位
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-30;
const int INF = 0x3f3f3f3f;
const int maxn = 5e4 + 5;
const int MOD = 1e9 + 7;
int n;
ull ans;
void dfs(ull x, int cur)
{
if (ans)
return;
if (cur > 19)
return;
if (x % n)
{
dfs(x * 10, cur + 1);
dfs(x * 10 + 1, cur + 1);
}
else
{
ans = x;
return;
}
}
int main()
{
while (scanf("%d", &n) && n)
{
ans = 0;
dfs(1, 0);
cout << ans << endl;
}
}
F - Prime Path POJ - 3126
題意
給出兩個素數,然後每次可以改變第一個素數的某一位數字 並且改變後的數字 也要是素數 求從第一個素數變到第二個素數最少需要多少步
思路
可以先預處理一個四位的素數表
然後我們發現,對於每一個數 我們都有9 * 4 - 1種操作,也 就是說 每一位上的數 都可以改變一次 然後成爲一個新數,然後只要判斷一下 改變之後的數 有沒有被訪問過並且是素數 ,滿足的話 就壓入隊列 BFS 就可以了
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back
#define bug puts("***bug***");
//#define gets gets_s
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <string, int> psi;
typedef pair <string, string> pss;
typedef pair <double, int> pdi;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4 + 10;
const int MOD = 1e9 + 7;
bool prime[maxn];
int visit[maxn];
void isprime()
{
CLR(prime, true);
prime[1] = false;
for (int i = 2; i < maxn; i++)
{
if (prime[i] == true)
{
for (int j = 2 * i; j < maxn; j += i)
prime[j] = false;
}
}
}
int n, m;
struct node
{
int digit[4];
int step, num;
void tran()
{
num = 0;
for (int i = 0; i < 4; i++)
num = num * 10 + digit[i];
}
};
bool ok(int num)
{
if (prime[num] == false || num < 1000 || num > 10000 || visit[num] == 1)
return false;
return true;
}
int bfs()
{
queue <node> q;
CLR(visit, 0);
node tmp;
int num = n;
tmp.num = n;
for (int i = 3; i >= 0; i--)
{
tmp.digit[i] = num % 10;
num /= 10;
}
tmp.step = 0;
q.push(tmp);
visit[n] = 1;
while (!q.empty())
{
node u = q.front(), v;
q.pop();
if (u.num == m)
return u.step;
v.step = u.step + 1;
for (int i = 0; i < 4; i++)
{
for (int k = 0; k < 4; k++)
v.digit[k] = u.digit[k];
for (int j = 0; j <= 9; j++)
{
v.digit[i] = j;
v.tran();
if (ok(v.num))
{
q.push(v);
visit[v.num] = 1;
}
}
}
}
return -1;
}
int main()
{
isprime();
int t;
cin >> t;
while (t--)
{
scanf("%d%d", &n, &m);
int ans = bfs();
if (ans < 0)
puts("Impossible");
else
cout << ans << endl;
}
}
G - Shuffle’m Up POJ - 3087
題意
給出連個字符串
每一次的操作 都是 先將s2的第一位放在目標串的第一位 再將S1的第一位放在目標串的第二位 然後是S2的第二位。。s1的第二位 這樣交叉疊放 組成一個目標串 分離的話 是 目標串的前N爲 組成S2 後N爲組成S1 求最少需要幾次轉換 能夠是的給出的S1和S2 能夠變成 S3
不行的話 輸出-1
思路
說是搜索,不如說是模擬吧。。
記錄訪問狀態 然後 BFS(模擬) 一下就好了
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back
#define bug puts("***debug***");
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = (1 << 15) + 10;
const int MOD = 1e9 + 7;
int c;
string s1, s2, s3;
struct node
{
string s1, s2, s;
int step;
void tran()
{
s1.clear();
s2.clear();
int len = s.size();
int i = 0;
for (; i < c; i++)
s1 += s[i];
for (; i < len; i++)
s2 += s[i];
}
};
map <string, int> vis;
string Union(string s1, string s2)
{
string ans = "";
for (int i = 0; i < c; i++)
{
ans += s2[i];
ans += s1[i];
}
return ans;
}
int bfs()
{
queue <node> q;
vis.clear();
node tmp;
tmp.step = 1;
tmp.s1 = s1, tmp.s2 = s2;
tmp.s = Union(s1, s2);
tmp.tran();
vis[tmp.s] = 1;
q.push(tmp);
while (!q.empty())
{
node u = q.front();
q.pop();
if (u.s == s3)
return u.step;
u.s = Union(u.s1, u.s2);
if (vis[u.s] == 0)
{
vis[u.s] = 1;
u.tran();
u.step++;
q.push(u);
}
}
return -1;
}
int main()
{
int t;
cin >> t;
int count = 1;
while (t--)
{
scanf("%d", &c);
cin >> s1 >> s2 >> s3;
printf("%d %d\n", count++, bfs());
}
}
H - Pots POJ - 3414
題意
給出A B 兩個杯子 對於每個杯子 有三種操作
第一種是將杯子中的水裝滿
第二種是將杯子中的水全部倒掉
第三種是將A中的水倒入B中 如果A中的水體積>B中的剩餘體積,那麼A倒滿B後剩下的水留下A中
最後求 A杯子或者 B杯子中 存在恰好C升水 需要多少步
思路
需要最少多少步 那麼自然就是想到 BFS
和之前的數字變化一樣
這也就是多了三種抽象的操作而已
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 5;
const int MOD = 1e9 + 7;
/*
0 FILL 1
1 FILL 2
2 DROP 1
3 DROP 2
4 POUR 1 2
5 POUR 2 1
*/
int visit[maxn][maxn];
vector <int> ans;
int flag;
int a, b, c;
struct node
{
int a, b;
vector <int> v;
};
void bfs()
{
queue <node> q;
node tmp;
tmp.a = 0;
tmp.b = 0;
tmp.v.clear();
q.push(tmp);
visit[0][0] = 1;
while (!q.empty())
{
node u = q.front(), v;
q.pop();
if (u.a == c || u.b == c)
{
flag = 1;
ans = u.v;
return;
}
if (u.a < a)
{
v.a = a;
v.b = u.b;
if (visit[v.a][v.b] == 0)
{
v.v = u.v;
v.v.pb(0);
q.push(v);
visit[v.a][v.b] = 1;
}
}
if (u.b < b)
{
v.a = u.a;
v.b = b;
if (visit[v.a][v.b] == 0)
{
v.v = u.v;
v.v.pb(1);
q.push(v);
visit[v.a][v.b] = 1;
}
}
if (u.a > 0)
{
v.a = 0;
v.b = u.b;
if (visit[v.a][v.b] == 0)
{
v.v = u.v;
v.v.pb(2);
q.push(v);
visit[v.a][v.b] = 1;
}
}
if (u.b > 0)
{
v.a = u.a;
v.b = 0;
if (visit[v.a][v.b] == 0)
{
v.v = u.v;
v.v.pb(3);
q.push(v);
visit[v.a][v.b] = 1;
}
}
if (u.a < a)
{
int c = a - u.a;
if (u.b >= c)
{
v.b = u.b - c;
v.a = a;
}
else
{
v.b = 0;
v.a = u.a + u.b;
}
if (visit[v.a][v.b] == 0)
{
v.v = u.v;
v.v.pb(5);
q.push(v);
visit[v.a][v.b] = 1;
}
}
if (u.b < b)
{
int c = b - u.b;
if (u.a >= c)
{
v.a = u.a - c;
v.b = b;
}
else
{
v.a = 0;
v.b = u.a + u.b;
}
if (visit[v.a][v.b] == 0)
{
v.v = u.v;
v.v.pb(4);
q.push(v);
visit[v.a][v.b] = 1;
}
}
}
}
int main()
{
map <int, string> M;
M[0] = "FILL(1)";
M[1] = "FILL(2)";
M[2] = "DROP(1)";
M[3] = "DROP(2)";
M[4] = "POUR(1,2)";
M[5] = "POUR(2,1)";
CLR(visit, 0);
scanf("%d%d%d", &a, &b, &c);
flag = 0;
bfs();
if (flag == 0)
printf("impossible\n");
else
{
int len = ans.size();
cout << len << endl;
for (int i = 0; i < len; i++)
cout << M[ans[i]] << endl;
}
}
I - Fire Game FZU - 2150
題意
給出一張圖
‘#’ 代表草 可以燃燒
‘.’ 代表空地 不能燃燒
有兩個人 可以選擇兩堆草點火 (可以是同一堆草)
最後求所有草都被點燃的最少時間
一堆草被點燃後 在一秒鐘後 是可以燃到它上下左右(如果存在的話)的草的
思路
先判斷連通塊 如果連通塊個數 > 2 那麼就是不可能完成目標的
然後枚舉任意兩塊草 去BFS 更新答案
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back
#define bug puts("***debug***");
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 10;
const int MOD = 1e9 + 7;
int G[10][10];
int visit[10][10];
int n, m;
int Move[4][2] =
{
-1, 0,
1, 0,
0,-1,
0, 1,
};
bool ok(int x, int y)
{
if (x < 0 || x >= n || y < 0 || y >= m || G[x][y] == 0 || visit[x][y] == 1)
return false;
return true;
}
void find(int x, int y)
{
int nx, ny;
for (int i = 0; i < 4; i++)
{
nx = x + Move[i][0];
ny = y + Move[i][1];
if (ok(nx, ny))
{
visit[nx][ny] = 1;
find(nx, ny);
}
}
}
struct node
{
int x, y;
}q[maxn];
queue <node> qq;
int ans;
bool judge()
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (G[i][j] == 1 && visit[i][j] == 0)
return false;
}
}
return true;
}
void bfs(int step)
{
int len = qq.size();
if (judge() == true)
{
ans = min(ans, step);
return;
}
for (int i = 0; i < len; i++)
{
node u = qq.front(), v;
qq.pop();
for (int j = 0; j < 4; j++)
{
v.x = u.x + Move[j][0];
v.y = u.y + Move[j][1];
if (ok(v.x, v.y))
{
qq.push(v);
visit[v.x][v.y] = 1;
}
}
}
if (qq.size())
bfs(step + 1);
else
return;
}
void init()
{
CLR(G, 0);
CLR(q, 0);
}
int main()
{
int t;
cin >> t;
for (int T = 1; T <= t; T++)
{
init();
scanf("%d%d", &n, &m);
char c;
int pos = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
scanf(" %c", &c);
if (c == '#')
{
G[i][j] = 1;
q[pos].x = i, q[pos].y = j;
pos++;
}
}
}
int tot = 0; // 找連通塊 連通塊個數 > 2 就是不可能實現要求的
CLR(visit, 0);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (G[i][j] == 1 && visit[i][j] == 0)
{
tot++;
visit[i][j] = 1;
find(i, j);
}
}
}
printf("Case %d: ", T);
if (tot > 2)
cout << -1 << endl;
else
{
ans = INF;
for (int i = 0; i < pos; i++)
{
for (int j = 0; j < pos; j++)
{
while (!qq.empty())
qq.pop();
CLR(visit, 0);
qq.push(q[i]);
qq.push(q[j]);
visit[q[i].x][q[i].y] = visit[q[j].x][q[j].y] = 1;
bfs(0);
}
}
cout << ans << endl;
}
}
}
J - Fire! UVA - 11624
題意
給出一張地圖
‘J’表示起點
‘F’表示火源(可能不止一個)
然後火源每秒鐘會向四周擴散
求J逃出地圖最少需要花費的時間(不可能逃出的話輸出”IMPOSSIBLE”)
思路
先讓火走 再讓人走
爲什麼要先讓火走 因爲
比如說
“####”
“##J.”
“###F”
“####”
如果先讓人走 發現 人是可以走到右邊的
但實際上 這一秒 火也會燒過來 也就是說 人走到這裏的時候 應該是被燒死了。。
BFS 兩個隊列 一個保存火的狀態,一個保存人的狀態
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1);
const double E = exp(1);
const double eps = 1e-30;
const int INF = 0x3f3f3f3f;
const int maxn = 1e3 + 5;
const int MOD = 1e9 + 7;
string G[maxn];
int Move[8][2]
{
-1, 0,
1, 0,
0,-1,
0, 1,
-1, 1,
-1,-1,
1, 1,
1,-1,
};
int n, m;
int ans;
bool ok(int x, int y)
{
if (x < 0 || x >= n || y < 0 || y >= m || G[x][y] != '.' )
return false;
return true;
}
bool edge(int x, int y)
{
if (x == 0 || x == n - 1 || y == 0 || y == m - 1)
return true;
return false;
}
struct Node
{
int x, y, step;
}tmp;
queue <Node> fire, q;
void bfs()
{
int len = fire.size();
for (int i = 0; i < len; i++)
{
int x = fire.front().x;
int y = fire.front().y;
fire.pop();
for (int j = 0; j < 4; j++)
{
tmp.x = x + Move[j][0];
tmp.y = y + Move[j][1];
if (ok(tmp.x, tmp.y))
{
G[tmp.x][tmp.y] = 'F';
fire.push(tmp);
}
}
}
len = q.size();
for (int i = 0; i < len; i++)
{
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
if (edge(x, y))
{
ans = step;
return;
}
for (int j = 0; j < 4; j++)
{
tmp.x = x + Move[j][0];
tmp.y = y + Move[j][1];
if (ok(tmp.x, tmp.y))
{
tmp.step = step + 1;
G[tmp.x][tmp.y] = '*';
q.push(tmp);
}
}
}
if (q.size())
bfs();
}
int main()
{
int t;
cin >> t;
while (t--)
{
while (!fire.empty())
fire.pop();
while (!q.empty())
q.pop();
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
{
cin >> G[i];
for (int j = 0; j < m; j++)
{
if (G[i][j] == 'J')
{
tmp.x = i;
tmp.y = j;
tmp.step = 0;
q.push(tmp);
G[i][j] = '.';
}
else if (G[i][j] == 'F')
{
tmp.x = i;
tmp.y = j;
fire.push(tmp);
}
}
}
ans = -1;
bfs();
if (ans == -1)
printf("IMPOSSIBLE\n");
else
printf("%d\n", ans + 1);
}
}
K - 迷宮問題 POJ - 3984
思路
這個就是簡單的迷宮問題,用BFS
然後難點可能在於路徑的輸出
兩種方式
0.在結構體中開一個vector 將路徑都保存下來
1.開一個pre[][] 數組 最後遞歸輸出
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1);
const double E = exp(1);
const double eps = 1e-30;
const int INF = 0x3f3f3f3f;
const int maxn = 5e4 + 5;
const int MOD = 1e9 + 7;
int G[5][5];
int v[5][5];
int Move[4][2]
{
-1, 0,
1, 0,
0,-1,
0, 1,
};
struct Node
{
int x, y;
vector <pii> ans;
}tmp;
vector <pii> ans;
queue <Node> q;
bool ok(int x, int y)
{
if (x < 0 || x >= 5 || y < 0 || y >= 5 || v[x][y] || G[x][y])
return false;
return true;
}
void bfs()
{
tmp.x = 0;
tmp.y = 0;
tmp.ans.pb(pii(0, 0));
v[tmp.x][tmp.y] = 1;
q.push(tmp);
while (!q.empty())
{
int x = q.front().x;
int y = q.front().y;
ans = q.front().ans;
q.pop();
if (x == 4 && y == 4)
return;
for (int i = 0; i < 4; i++)
{
tmp.x = x + Move[i][0];
tmp.y = y + Move[i][1];
if (ok(tmp.x, tmp.y))
{
tmp.ans = ans;
tmp.ans.pb(pii(tmp.x, tmp.y));
q.push(tmp);
tmp.ans.pop_back();
v[tmp.x][tmp.y] = 1;
}
}
}
}
int main()
{
CLR(v);
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
scanf("%d", &G[i][j]);
}
bfs();
vector <pii>::iterator it;
for (it = ans.begin(); it != ans.end(); it++)
{
printf("(%d, %d)\n", (*it).first, (*it).second);
}
}
L - Oil Deposits HDU - 1241
題意
一塊油田 的 上下左右 左上 左下 右上 右下 如果也是油田 那麼認爲這些油田是連通的
最後找出有多少塊連通的油田
思路
先遍歷這個圖 然後遇到油田 就ans++
然後BFS將這個圖四周滿足情況的油田都變成’*’ 就可以了
或者開個訪問標記數組也可以
其實本質就是找連通塊
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1);
const double E = exp(1);
const double eps = 1e-30;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 5;
const int MOD = 1e9 + 7;
string G[maxn];
int Move[8][2]
{
-1, 0,
1, 0,
0,-1,
0, 1,
-1, 1,
-1,-1,
1, 1,
1,-1,
};
int n, m;
bool ok(int x, int y)
{
if (x < 0 || x >= n || y < 0 || y >= m || G[x][y] == '*')
return false;
return true;
}
void dfs(int x, int y)
{
G[x][y] = '*';
for (int i = 0; i < 8; i++)
{
int nx = x + Move[i][0];
int ny = y + Move[i][1];
if (ok(nx, ny))
dfs(nx, ny);
}
}
int main()
{
while (scanf("%d%d", &n, &m) && m)
{
for (int i = 0; i < n; i++)
cin >> G[i];
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (G[i][j] == '@')
{
ans++;
dfs(i, j);
}
}
}
cout << ans << endl;
}
}
M - 非常可樂 HDU - 1495
思路
其實每次有六種操作
0. s -> n
1. s -> m
2. n -> s
3. n -> m
4. m -> s
5. m -> n
其實可以發現 n + m == s
所以最後一定是 杯子容量大一點的那個杯子裝了一半的可樂
BFS
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1);
const double E = exp(1);
const double eps = 1e-30;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 5;
const int MOD = 1e9 + 7;
struct node
{
int s, n, m, t;
};
int s, n, m;
int vis[maxn][maxn];
queue <node> q;
int bfs()
{
CLR(vis);
node temp;
temp.s = s;
temp.n = 0;
temp.m = 0;
temp.t = 0;
vis[n][m] = 1;
q.push(temp);
while (!q.empty())
{
node u = q.front(), v;
q.pop();
if (u.n == s / 2 && u.s == s / 2)
return u.t;
if (u.s && u.n != n) // s -> n
{
int c = n - u.n;
if (u.s >= c)
{
v.s = u.s - c;
v.n = n;
}
else
{
v.s = 0;
v.n = u.n + u.s;
}
v.m = u.m;
if (vis[v.n][v.m] == 0)
{
v.t = u.t + 1;
q.push(v);
vis[v.n][v.m] = 1;
}
}
if (u.s && u.m != m) // s -> m
{
int c = m - u.m;
if (u.s >= c)
{
v.s = u.s - c;
v.m = m;
}
else
{
v.s = 0;
v.m = u.m + u.s;
}
v.n = u.n;
if (vis[v.n][v.m] == 0)
{
v.t = u.t + 1;
q.push(v);
vis[v.n][v.m] = 1;
}
}
if (u.n && u.s != s) // n -> s
{
int c = s - u.s;
if (u.n >= c)
{
v.n = u.n - c;
v.s = s;
}
else
{
v.n = 0;
v.s = u.s + u.n;
}
v.m = u.m;
if (vis[v.n][v.m] == 0)
{
v.t = u.t + 1;
q.push(v);
vis[v.n][v.m] = 1;
}
}
if (u.n && u.m != m) // n -> m
{
int c = m - u.m;
if (u.n >= c)
{
v.n = u.n - c;
v.m = m;
}
else
{
v.n = 0;
v.m = u.m + u.n;
}
v.s = u.s;
if (vis[v.n][v.m] == 0)
{
v.t = u.t + 1;
q.push(v);
vis[v.n][v.m] = 1;
}
}
if (u.m && u.s != s) // m -> s
{
int c = s - u.s;
if (u.m >= c)
{
v.m = u.m - c;
v.s = s;
}
else
{
v.m = 0;
v.s = u.s + u.m;
}
v.n = u.n;
if (vis[v.n][v.m] == 0)
{
v.t = u.t + 1;
q.push(v);
vis[v.n][v.m] = 1;
}
}
if (u.m && u.n != n) // m -> n
{
int c = n - u.n;
if (u.m >= c)
{
v.m = u.m - c;
v.n = n;
}
else
{
v.m = 0;
v.n = u.n + u.m;
}
v.s = u.s;
if (vis[v.n][v.m] == 0)
{
v.t = u.t + 1;
q.push(v);
vis[v.n][v.m] = 1;
}
}
}
return 0;
}
int main()
{
while (scanf("%d%d%d", &s, &n, &m) && (s || n || m))
{
while (!q.empty())
q.pop();
if (s % 2)
puts("NO");
else
{
if (n < m)
swap(n, m);
int ans = bfs();
if (ans)
cout << ans << endl;
else
puts("NO");
}
}
}
N - Find a way HDU - 2612
題意
@表示KFC
Y M 分別表示兩個人
一張地圖中可能有多少KFC 然後要找一個KFC 使得 兩個人到達那裏的路徑之和最小
思路
兩次BFS 第一次 求出 Y 到達每個KFC的路徑
第二次 求出 M 到達每個KFC 的路徑
然後FOR 一遍 找一下 兩個人到達哪個KFC的路徑之和最小就可以了
不要 對於每個KFC 都去重新BFS 算出兩個人的路徑距離啊。。。。TTT
AC代碼
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a) memset(a, 0, sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1);
const double E = exp(1);
const double eps = 1e-30;
const int INF = 0x3f3f3f3f;
const int maxn = 5e4 + 5;
const int MOD = 1e9 + 7;
int Move[][2]
{
-1, 0, // up
1, 0, // down
0,-1, // left
0, 1, // righ
};
struct Node
{
int x, y, step;
}tmp;
string G[205];
int v[205][205];
int dis[205][205][2];
int n, m;
int sx[2], sy[2];
queue <Node> q;
bool ok(int x, int y)
{
if (x < 0 || x >= n || y < 0 || y >= m || G[x][y] == '#' || v[x][y] == 1)
return false;
return true;
}
void bfs(int vis)
{
while (!q.empty())
{
int x = q.front().x;
int y = q.front().y;
int step = q.front().step;
q.pop();
if (G[x][y] == '@')
dis[x][y][vis] = min(dis[x][y][vis], step);
for (int i = 0; i < 4; i++)
{
tmp.x = x + Move[i][0];
tmp.y = y + Move[i][1];
tmp.step = step + 1;
if (ok(tmp.x, tmp.y))
{
q.push(tmp);
v[tmp.x][tmp.y] = 1;
}
}
}
}
int main()
{
while (~scanf("%d%d", &n, &m))
{
for (int i = 0; i < n; i++)
{
cin >> G[i];
for (int j = 0; j < m; j++)
{
if (G[i][j] == 'Y')
{
sx[0] = i;
sy[0] = j;
}
else if (G[i][j] == 'M')
{
sx[1] = i;
sy[1] = j;
}
}
}
memset(dis, 0x3f, sizeof(dis));
for (int i = 0; i < 2; i++)
{
CLR(v);
tmp.x = sx[i];
tmp.y = sy[i];
v[tmp.x][tmp.y] = 1;
tmp.step = 0;
while (!q.empty())
q.pop();
q.push(tmp);
bfs(i);
}
int ans = INF;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (G[i][j] == '@')
ans = min(ans, dis[i][j][0] + dis[i][j][1]);
}
}
//for (int i = 0; i < pos; i++)
//{
// //mx = ex[i];
// //my = ey[i];
// //CLR(v);
// //tmp.x = sx[0];
// //tmp.y = sy[0];
// //tmp.step = 0;
// //v[tmp.x][tmp.y] = 1;
// //while (!q.empty())
// // q.pop();
// //q.push(tmp);
// //tar = 0;
// //bfs();
// //CLR(v);
// //tmp.x = sx[1];
// //tmp.y = sy[1];
// //tmp.step = 0;
// //v[tmp.x][tmp.y] = 1;
// //while (!q.empty())
// // q.pop();
// //q.push(tmp);
// CLR(v);
// tar = 0;
// while (!q.empty())
// q.pop();
// tmp.x = ex[i];
// tmp.y = ey[i];
// tmp.step = 0;
// q.push(tmp);
// flag = 0;
// v[tmp.x][tmp.y] = 1;
// bfs();
// ans = min(ans, tar);
//}
cout << ans * 11 << endl;
}
}