搜索问题
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;
}
}