专题一 简单搜索
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;
}