搜索入门练练练!
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=65959#overview
感谢bin神带我第一次飞飞飞。
A:
题意:
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。- - 中文题。
解析:
每行往下dfs,水。
代码:
#include <stdio.h>
#include <string.h>
const int maxn = 10 + 10;
char g[maxn][maxn];
bool vis[maxn];
int ans;
int n;
void dfs(int row, int k)
{
if (row == n)
{
if (k == 0)
{
ans++;
}
return ;
}
dfs(row + 1, k);
for (int i = 0; i < n; i++)
{
if (g[row][i] == '#' && !vis[i])
{
vis[i] = true;
dfs(row + 1, k - 1);
vis[i] = false;
}
}
return;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int k;
while (~scanf("%d%d", &n, &k))
{
if (n == -1 && k == -1)
break;
for (int i = 0; i < n; i++)
{
scanf("%s", g[i]);
}
memset(vis, false, sizeof(vis));
ans = 0;
dfs(0, k);
printf("%d\n", ans);
}
return 0;
}
B:
题意:
3D迷宫,bfs。
解析:
加一维表示空间就好惹,从bin神那里学来的step -1 标记法,再也不用vis担心我的搜索重复了。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 30 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int dir[][3] = {{0, -1, 0}, {0, 1, 0}, {-1, 0, 0}, {1, 0, 0}, {0, 0, -1}, {0, 0, 1}};
int l, r, c;
int g[maxn][maxn][maxn];
int dp[maxn][maxn][maxn];
struct Node
{
int x, y, z;
Node(int _x, int _y, int _z)
{
x = _x;
y = _y;
z = _z;
}
};
bool ok(int x, int y, int z)
{
if (0 <= x && x < r && 0 <= y && y < c && 0 <= z && z < l && g[z][x][y] != '#')
return true;
return false;
}
int bfs(int sx, int sy, int sz, int ex, int ey, int ez)
{
memset(dp, -1, sizeof(dp));
queue<Node> q;
q.push(Node(sx, sy, sz));
dp[sx][sy][sz] = 0;
while (!q.empty())
{
Node now = q.front();
q.pop();
int x = now.x;
int y = now.y;
int z = now.z;
//cout << x << " " << y << " " << z << endl;
if (x == ex && y == ey && z == ez)
{
return dp[x][y][z];
}
for (int i = 0; i < 6; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
int nz = z + dir[i][2];
if (ok(nx, ny, nz))
{
if (dp[nx][ny][nz] == -1)
{
dp[nx][ny][nz] = dp[x][y][z] + 1;
q.push(Node(nx, ny, nz));
}
}
}
}
return -1;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d%d%d", &l, &r, &c))
{
if (!l && !r && !c)
break;
getchar();
for (int i = 0; i < l; i++)
{
for (int j = 0; j < r; j++)
{
for (int k = 0; k < c; k++)
{
scanf("%c", &g[i][j][k]);
}
getchar();
}
getchar();
}
int sx, sy, sz, ex, ey, ez;
for (int i = 0; i < l; i++)
{
for (int j = 0; j < r; j++)
{
for (int k = 0; k < c; k++)
{
if (g[i][j][k] == 'S')
{
sx = j;
sy = k;
sz = i;
}
if (g[i][j][k] == 'E')
{
ex = j;
ey = k;
ez = i;
}
}
}
}
// cout << sx << " " << sy << " " << sz << " " << endl;cout << ex << " " << ey << " " << ez << " " << endl;
int ans = bfs(sx, sy, sz, ex, ey, ez);
if (ans == -1)
{
printf("Trapped!\n");
}
else
{
printf("Escaped in %d minute(s).\n", ans);
}
}
return 0;
}
C:
题意:
抓牛,牛在一个位置,你在一个位置,你的坐标可以+1 or -1 or *2,最短抓到牛的时间。
解析:
bfs,加了一点点剪枝。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int step[maxn];
int bfs(int n, int k)
{
memset(step, -1, sizeof(step));
queue<int> q;
q.push(n);
step[n] = 0;
while (!q.empty())
{
int now = q.front();
q.pop();
if (now == k)
return step[now];
int next;
/// - 1
next = now - 1;
if (0 <= next && step[next] == -1)///剪枝
{
step[next] = step[now] + 1;
q.push(next);
}
/// + 1
next = now + 1;
if (next < maxn && step[next] == -1)///剪枝
{
step[next] = step[now] + 1;
q.push(next);
}
/// * 2
next = now * 2;
if (next < maxn && step[next] == -1)///剪枝
{
step[next] = step[now] + 1;
q.push(next);
}
}
return 0;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int n, k;
while (~scanf("%d%d", &n, &k))
{
printf("%d\n", bfs(n, k));
}
return 0;
}
D:
题意:
题目看了半天才懂,给一个n*m的01矩阵,0代表白,1代表黑。
现在要你来翻转他们,每次翻转一个点,这个点的上下左右的点都会翻转,1翻成0,0翻转成1。
现在要你求最短的翻转次数,使得这个矩阵全白,that means 全为0。
解析:
参考了网上一些大牛的做法。
首先,如果一个点翻转两次和没翻是没差的,所以一个点最多只翻一次。
n,m并不大,只有15,所以用状态压缩把010101的状态保存下来,然后暴力下去。
为了保证字典序最小,从第一行的右向左开始暴,每次第一行确定了以后,剩下的行的状态也就随之确定了(想一想,为什么)。
然后全部搞完以后,判断最后一行是否全为0,若是,则此次翻转成功,更新最小值,就好啦。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 15 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
int cnt;
int g[maxn][maxn];
int t[maxn][maxn];
int flipNum[maxn][maxn];
void flip(int x, int y)
{
cnt++;
flipNum[x][y] = 1;
t[x][y] ^= 1;
for (int i = 0; i < 4; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (0 <= nx && nx < n && 0 <= ny && ny < m)
{
t[nx][ny] ^= 1;
}
}
return;
}
bool ok(int state)
{
cnt = 0;
memcpy(t, g, sizeof(t));
for (int i = 0; i < m; i++)
{
if (state & (1 << (m - i - 1)))
{
flip(0, i);
}
}
for (int i = 1; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (t[i - 1][j])
{
flip(i, j);
}
}
}
for (int i = 0; i < m; i++)
{
if (t[n - 1][i])
{
return false;
}
}
return true;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d%d", &n, &m))
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
scanf("%d", &g[i][j]);
}
}
int ans = n * m + 1;
int state = -1;
memset(flipNum, 0, sizeof(flipNum));
for (int i = 0; i < (1 << m); i++)
{
if (ok(i) && cnt < ans)
{
ans = cnt;
state = i;
}
}
memset(flipNum, 0, sizeof(flipNum));
if (state != -1)
{
ok(state);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%d%c", flipNum[i][j], j < m - 1 ? ' ' : '\n');
}
}
}
else
{
printf("IMPOSSIBLE\n");
}
}
return 0;
}
E:
题意:
给一个数n,求这个数的倍数里面,只含0、1的数。
解析:
看别人暴了一个20位的数,用unsigned __int64水过。
小u的博客上有数论的解法。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define UI64 unsigned __int64
using namespace std;
const int maxn = 15;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int n;
bool flag;
void dfs(UI64 t, int dep)
{
if (flag)
return;
if (dep >= 20)
return;
if (t % n == 0)
{
flag = true;
printf("%I64u\n", t);
return;
}
dfs(t * 10, dep + 1);
dfs(t * 10 + 1, dep + 1);
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (scanf("%d", &n) && n)
{
flag = false;
dfs(1, 0);
}
return 0;
}
F:
题意:
素数路径,给俩素数,每次只能改变一个位置的数,并且改变成的这个数也要是素数,求最少变换次数。
解析:
bfs,素数处理方法,刚开始用数论里面总结的素数打表法竟然出错了,我。。。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 1e4 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int prime[maxn];
bool isPrime[maxn];
int nprime;
void primeTable()
{
int i,j;
for(i = 1000; i <= maxn; i++)
{
for(j = 2; j < i; j++)
if(i % j == 0)
{
isPrime[i] = false;
break;
}
if(j == i)
isPrime[i] = true;
}
}
bool flag;
int step[maxn];
int bfs(int s, int e)
{
int num[5];
memset(step, -1, sizeof(step));
queue<int> q;
q.push(s);
step[s] = 0;
while (!q.empty())
{
int now = q.front();
q.pop();
if (now == e)
{
flag = true;
return step[now];
}
int t = now;
for (int i = 0; i < 4; i++)
{
num[i] = t % 10;
t /= 10;
}
for (int i = 0; i < 4; i++)
{
t = num[i];
for (int j = 0; j <= 9; j++)
{
if (j != t)
{
num[i] = j;
int next = 0;
for (int k = 3; k >= 0; k--)
next = next * 10 + num[k];
if (step[next] == -1 && isPrime[next])
{
step[next] = step[now] + 1;
q.push(next);
}
}
num[i] = t;
}
}
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
primeTable();
while (ncase--)
{
int s, e;
scanf("%d%d", &s, &e);
flag = false;
int ans = bfs(s, e);
if (flag)
printf("%d\n", ans);
else
printf("Impossible\n");
}
return 0;
}
G:
题意:
又是一道题意题。
给俩字符串,每次洗牌,洗牌规则是交叉交叉交叉,问几次能到达目标串。
解析:
用set来替代Hash判断是否有重复存在。
然后得到这个思路模拟模拟模拟就好了。
具体看代码。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#include <set>
#define LL long long
using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
int ca = 1;
set<string> shuf;
string aim, str, s1, s2;
int n;
while (ncase--)
{
cin >> n >> s1 >> s2 >> aim;
str.resize(2 * n);
shuf.clear();
bool found = false;
int cnt = 0;
while (!found)
{
cnt++;
for (int i = 0; i < n; i++)
{
str[i * 2] = s2[i];
str[i * 2 + 1] = s1[i];
}
for (int i = 0; i < n; i++)
{
s1[i] = str[i];
s2[i] = str[i + n];
}
if (str == aim)
{
found = true;
break;
}
if (shuf.find(str) == shuf.end())
shuf.insert(str);
else
break;
}
printf("%d ", ca++);
if (found)
printf("%d\n", cnt);
else
printf("-1\n");
}
return 0;
}
H:
题意:
倒水问题,给你无限量的水,两容量分别为a, b的杯子,问你能否倒出 c 状态容量的水。
基本操作有:fill1 ...fill2... drop1 ...drop2 ...pour 1 -> 2... pour 2 -> 1...
解析:
按照题意一路dfs暴下去就好了。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 200 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int a, b, c, ans;
string tstring[10000 + 10], astring[1000 + 10];
bool flag, vis[100 + 10][100 + 10];
void dfs(int x, int y, int dep)
{
if (ans < dep)
return;
if (x == c || y == c)
{
if (dep < ans)
{
ans = dep;
flag = true;
for (int i = 0; i < ans; i++)
astring[i] = tstring[i];
}
}
//fill 1
if (x < a && !vis[a][y])
{
vis[a][y] = true;
tstring[dep] = "FILL(1)";
dfs(a, y, dep + 1);
vis[a][y] = false;
}
//fill 2
if (y < b && !vis[x][b])
{
vis[x][b] = true;
tstring[dep] = "FILL(2)";
dfs(x, b, dep + 1);
vis[x][b] = false;
}
//drop 1
if (0 < x && !vis[0][y])
{
vis[0][y] = true;
tstring[dep] = "DROP(1)";
dfs(0, y, dep + 1);
vis[0][y] = false;
}
//drop2
if (0 < y && !vis[x][0])
{
vis[x][0] = true;
tstring[dep] = "DROP(2)";
dfs(x, 0, dep + 1);
vis[x][0] = false;
}
//pour 1 -> 2
if (0 < x && y < b)
{
int t;
if (x < b - y)
t = x;
else
t = b - y;
if (!vis[x - t][y + t])
{
vis[x - t][y + t] = true;
tstring[dep] = "POUR(1,2)";
dfs(x - t, y + t, dep + 1);
vis[x - t][y + t] = false;
}
}
//pour 2 -> 1
if (0 < y && x < a)
{
int t;
if (y < a - x)
t = y;
else
t = a - x;
if (!vis[x + t][y - t])
{
vis[x + t][y - t] = true;
tstring[dep] = "POUR(2,1)";
dfs(x + t, y - t, dep + 1);
vis[x + t][y - t] = false;
}
}
return ;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d%d%d", &a, &b, &c))
{
memset(vis, false, sizeof(vis));
vis[0][0] = true;
flag = false;
ans = inf;
dfs(0, 0, 0);
if (flag)
{
printf("%d\n", ans);
for (int i = 0; i < ans; i++)
{
cout << astring[i] << endl;
}
}
else
{
printf("impossible\n");
}
}
return 0;
}
I:
题意:
我大fzu的题!鸡冻。
给一张图,图上的#代表一个草,现在你可以hentai的找两个干草点来点燃他们,火势每秒会向上下左右四个方向蔓延。
问最初只点两个草的情况下最快能多快把所有草点燃,若不能输出-1。
解析:
干草点不多,枚举两个#起点来做。
每枚举两个#,就把两个点扔到bfs里面加到队列里,求最短烧完时间。
很显然,要把所有草都点燃,bfs时最后出队列的一定就是时间点了。
然后枚举判断所有#是否都被点燃,若没有,则继续枚举,若有,更新。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 10 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
char g[maxn][maxn];
struct Node
{
int x, y;
Node (){}
Node(int _x, int _y)
{
x = _x;
y = _y;
}
} p[maxn * maxn];
int step[maxn][maxn];
int bfs(Node a, Node b)
{
memset(step, -1, sizeof(step));
int res = 0;
queue<Node> q;
q.push(a);
q.push(b);
step[a.x][a.y] = 0;
step[b.x][b.y] = 0;
while (!q.empty())
{
Node now = q.front();
q.pop();
int x = now.x;
int y = now.y;
res = step[x][y];
for (int i = 0; i < 4; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] == '#' && step[nx][ny] == -1)
{
step[nx][ny] = step[x][y] + 1;
q.push(Node(nx, ny));
}
}
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
int ca = 1;
scanf("%d", &ncase);
while (ncase--)
{
scanf("%d%d", &n, &m);
int cnt = 0;
for (int i = 0; i < n; i++)
{
scanf("%s", g[i]);
for (int j = 0; j < m; j++)
{
if (g[i][j] == '#')
{
p[cnt].x = i;
p[cnt++].y = j;
}
}
}
int ans = inf;
for (int i = 0; i < cnt; i++)
{
for (int j = i; j < cnt; j++)
{
int t = bfs(p[i], p[j]);
bool over = true;
for (int k = 0; k < n; k++)
{
for (int l = 0; l < m; l++)
{
if (step[k][l] == -1 && g[k][l] == '#')
{
over = false;
break;
}
}
if (!over)
break;
}
if (over)
{
if (t < ans)
ans = t;
}
}
}
printf("Case %d: ", ca++);
if (ans == inf)
{
printf("-1\n");
}
else
{
printf("%d\n", ans);
}
}
return 0;
}
J:
题意:
着火密室逃脱play。
给一张图,图上有不止一个着火点F,和上题一样,每秒火苗会往上下左右蔓延。
现在你,J,站在密室中的一个点,问你能否跑出这片火海。当你到达密室边界的时候就算逃脱成功。
解析:
我用了两次bfs,首先第一次先把fire烧到每个点的时间用fireStep保存下来, 相当于先分析火烧的方向与时间。
然后第二次就轮到你,J,来走了,同样是一步一步往外搜,当下个点的没有被火烧到 || 你到达下个点的时间早于火烧到的时间,就把这个点入队。
最后到达边界再+1你就活了!!
先是把出口的 y == m - 1写成n。。。
然后才发现了F可能不止一个地方开始烧。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 1000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
char g[maxn][maxn];
int fireStep[maxn][maxn];
int joesStep[maxn][maxn];
struct Node
{
int x, y;
Node(){}
Node(int _x, int _y)
{
x = _x;
y = _y;
}
};
void fireBfs()
{
memset(fireStep, -1, sizeof(fireStep));
queue<Node> q;
///not only one fire
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == 'F')
{
q.push(Node(i, j));
fireStep[i][j] = 0;
}
}
}
while (!q.empty())
{
Node now = q.front();
q.pop();
int x = now.x;
int y = now.y;
for (int i = 0; i < 4; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] != '#' && fireStep[nx][ny] == -1)
{
fireStep[nx][ny] = fireStep[x][y] + 1;
q.push(Node(nx, ny));
}
}
}
return;
}
int joesBfs()
{
memset(joesStep, -1, sizeof(joesStep));
queue<Node> q;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == 'J')
{
q.push(Node(i, j));
joesStep[i][j] = 0;
break;
}
}
}
while (!q.empty())
{
Node now = q.front();
q.pop();
int x = now.x;
int y = now.y;
if (x == 0 || x == n - 1 || y == 0 || y == m - 1)
{
return joesStep[x][y] + 1;
}
for (int i = 0; i < 4; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] != '#')
{
if (joesStep[nx][ny] == -1)
{
if (fireStep[nx][ny] == -1 || joesStep[x][y] + 1 < fireStep[nx][ny])
{
joesStep[nx][ny] = joesStep[x][y] + 1;
q.push(Node(nx, ny));
}
}
}
}
}
return -1;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
{
scanf("%s", g[i]);
}
fireBfs();
int ans = joesBfs();
if (ans == -1)
{
printf("IMPOSSIBLE\n");
}
else
{
printf("%d\n", ans);
}
}
return 0;
}
K:
题意:
给一个5*5的01迷宫,让你找从左上点(0, 0)到右下点(4, 4)的最短路径,打印。
解析:
这个迷宫这么小,随便搞吧!
结果,打印路径坑死了。。。
这不是和dp的打印路径很像嘛。。。
但是我用了指针。。。可能数据结构写顺手了。。。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 10 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int g[maxn][maxn];
struct Node
{
int x, y;
Node* pre;
// Node(int _x, int _y)
// {
// x = _x;
// y = _y;
// }
};
void print(Node* now)
{
if (now -> pre != NULL)
{
print(now -> pre);
printf("(%d, %d)\n", now -> x, now -> y);
}
}
void bfs(int x, int y)
{
queue<Node*> q;
Node* s = new Node;
g[x][y] = 1;
s -> x = x;
s -> y = y;
s -> pre = NULL;
q.push(s);
while (!q.empty())
{
Node* now = q.front();
q.pop();
int x = now -> x;
int y = now -> y;
//cout << now -> x << " " << now -> y << endl;
if (x == 4 && y == 4)
{
// cout << "ok" << endl;
printf("(0, 0)\n");
print(now);
return;
}
for (int i = 0; i < 4; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (0 <= nx && nx < 5 && 0 <= ny && ny < 5 && g[nx][ny] != 1)
{
Node* next = new Node;
g[nx][ny] = 1;
next -> x = nx;
next -> y = ny;
next -> pre = now;
q.push(next);
//cout << q.front() -> x << q.front() -> y << endl;
}
}
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
scanf("%d", &g[i][j]);
}
}
bfs(0, 0);
return 0;
}
L:
题意:
我的入门dfs题,其实是递归。
找八个方向的联通块有多少个。
解析:
枚举@,往下dfs,改@,出联通个数。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
int n, m;
char g[maxn][maxn];
void dfs(int x, int y)
{
g[x][y] = '.';
for (int i = 0; i < 8; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] == '@')
{
dfs(nx, ny);
}
}
return;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (scanf("%d%d", &n, &m) == 2)
{
if (!n && !m)
break;
for (int i = 0; i < n; i++)
{
scanf("%s", g[i]);
}
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == '@')
{
dfs(i, j);
ans++;
}
}
}
printf("%d\n", ans);
}
return 0;
}
M:
题意:
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。
因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。
但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升(正好装满一瓶)
它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。
聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
中文题~。
解析:
如果s是奇数,直接NO。
然后就和上面那道倒水题异曲同工了,区别只是这题多了个杯子,并且给定了初始水量。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int a, b, c;
int ans;
bool vis[maxn][maxn][maxn];
int target;
void dfs(int x, int y, int z, int dep)
{
if ((x == target && y == target) || (x == target && z == target) || (y == target && z == target))
{
if (dep < ans)
{
ans = dep;
}
return;
}
//x -> y
if (0 < x && y < b)
{
int t;
if (x < b - y)
t = x;
else
t = b - y;
if (!vis[x - t][y + t][z])
{
vis[x - t][y + t][z] = true;
dfs(x - t, y + t, z, dep + 1);
vis[x - t][y + t][z] = false;
}
}
//y -> x
if (0 < y && x < a)
{
int t;
if (y < a - x)
t = y;
else
t = a - x;
if (!vis[x + t][y - t][z])
{
vis[x + t][y - t][z] = true;
dfs(x + t, y - t, z, dep + 1);
vis[x + t][y - t][z] = false;
}
}
//x -> z
if (0 < x && z < c)
{
int t;
if (x < c - z)
t = x;
else
t = c - z;
if (!vis[x - t][y][z + t])
{
vis[x - t][y][z + t] = true;
dfs(x - t, y, z + t, dep + 1);
vis[x - t][y][z + t] = false;
}
}
//z -> x
if (0 < z && x < a)
{
int t;
if (z < a - x)
t = z;
else
t = a - x;
if (!vis[x + t][y][z - t])
{
vis[x + t][y][z - t] = true;
dfs(x + t, y, z - t, dep + 1);
vis[x + t][y][z - t] = false;
}
}
//y -> z
if (0 < y && z < c)
{
int t;
if (y < c - z)
t = y;
else
t = c - z;
if (!vis[x][y - t][z + t])
{
vis[x][y - t][z + t] = true;
dfs(x, y - t, z + t, dep + 1);
vis[x][y - t][z + t] = false;
}
}
//z -> y
if (0 < z && y < b)
{
int t;
if (z < b - y)
t = z;
else
t = b - y;
if (!vis[x][y + t][z - t])
{
vis[x][y + t][z - t] = true;
dfs(x, y + t, z - t, dep + 1);
vis[x][y + t][z - t] = false;
}
}
return;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d%d%d", &a, &b, &c))
{
if (!a && !b && !c)
break;
if (a % 2)
{
printf("NO\n");
}
else
{
if (b < c)
{
int t = b;
b = c;
c = t;
}
memset(vis, false, sizeof(vis));
ans = inf;
target = a / 2;
vis[a][0][0] = true;
dfs(a, 0, 0, 0);
if (ans == inf)
{
printf("NO\n");
}
else
{
printf("%d\n", ans);
}
}
}
return 0;
}
N:
题意:
你Y和你的好基友M,现在想见面,图上有好多家kfc @,现在找到一个kcf,使你到那里的距离+ 你基友到那里的距离最短。
解析:
TLE -> CE -> Wa -> MLE...-> Wa......... -> ac
思路是先用bfs找出你到每个kfc的最短距离,然后再用一次bfs找到你基友到每个kfc的最短距离。
然后遍历一次找最小值就行了。
坑点在于,可能有人到达不了其中的kfc,加的话就-1了。
然后MLE的原因是。。。。我刚开始输入了两次m,n。。。。。还有刚开始写的时候脑子有坑,*11 记成*6,查错查了半天。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 200 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int dir[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int n, m;
int step[5][maxn][maxn];
char g[maxn][maxn];
struct Node
{
int x, y;
Node(int _x, int _y)
{
x = _x;
y = _y;
}
};
void bfs(int sx, int sy, int key)
{
queue<Node> q;
q.push(Node(sx, sy));
step[key][sx][sy] = 0;
while (!q.empty())
{
Node now = q.front();
q.pop();
int x = now.x;
int y = now.y;
for (int i = 0; i < 4; i++)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if (0 <= nx && nx < n && 0 <= ny && ny < m && g[nx][ny] != '#' && step[key][nx][ny] == -1)
{
step[key][nx][ny] = step[key][x][y] + 1;
q.push(Node(nx, ny));
}
}
}
return;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (scanf("%d%d", &n, &m) == 2)
{
for (int i = 0; i < n; i++)
{
scanf("%s", g[i]);
}
int sx1, sy1, sx2, sy2;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == 'Y')
{
sx1 = i;
sy1 = j;
}
if (g[i][j] == 'M')
{
sx2 = i;
sy2 = j;
}
}
}
memset(step, -1, sizeof(step));
bfs(sx1, sy1, 1);
bfs(sx2, sy2, 2);
int t = inf;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == '@'&& step[1][i][j] != -1 && step[2][i][j] != -1)///可能有人到达不了其中的一个kfc
{
if (step[1][i][j] + step[2][i][j] < t)
t = step[1][i][j] + step[2][i][j];
}
}
}
printf("%d\n", t * 11);
}
return 0;
}
这些题刷了三天,大白还没有继续刷。
接下来搜索进阶估计要刷好几天,加上大白慢慢来吧。
(●—●)。