[bin神带我飞系列]专题一 搜索入门
来源:互联网 发布:apache参数优化 编辑:程序博客网 时间:2024/06/10 09:13
搜索入门练练练!
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 longusing 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 longusing 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 longusing 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 __int64using 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 longusing 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 longusing 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 longusing 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 longusing 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 longusing 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 longusing 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 longusing 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 longusing 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 longusing 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;}
这些题刷了三天,大白还没有继续刷。
接下来搜索进阶估计要刷好几天,加上大白慢慢来吧。
(●—●)。
- [bin神带我飞系列]专题一 搜索入门
- [kuangbin神带你飞]专题一 简单搜索
- 带你飞系列 - 一简单搜索
- kuangbin带你飞 专题一 简单搜索 (题解)
- Fire Game [kuangbin带你飞]专题一 简单搜索
- [kuangbin带你飞]专题一 简单搜索 总结
- Kuangbin带你飞专题一 简单搜索
- [kuangbin带你飞]专题一 简单搜索 D - Fliptile
- [kuangbin带你飞]专题一 简单搜索-J - Fire!
- [kuangbin带你飞]专题一 简单搜索 - H - Pots
- [kuangbin带你飞]专题一 简单搜索 A POJ1321
- [kuangbin带你飞]专题一 简单搜索 B POJ2251
- [kuangbin带你飞]专题一 简单搜索 C POJ3278
- [kuangbin带你飞]专题一 简单搜索 D poj3279
- [kuangbin带你飞]专题一 简单搜索 E POJ1426
- [kuangbin带你飞]专题一 简单搜索 F POJ3126
- [kuangbin带你飞]专题一 简单搜索 H POJ3414
- [kuangbin带你飞]专题一 简单搜索 G POJ3087
- 输入两个整数,将它们按由大到小的顺序输出。要求使用变量的引用
- Java基础第四讲
- string中c_str()、data()、copy(p,n)函数的用法
- 自己理解的C和OC的本质区别
- 继承的相关注意事项
- [bin神带我飞系列]专题一 搜索入门
- 《操作系统》——存储管理
- magento xml配置详解(2)
- java实现极简单的 TXT小说阅读器
- 微信开发二三事:功能应用三、点歌系统
- 截取字符串中的子串
- 简介jni(三)
- ORACLE9i_性能调优基础四(Buffer Cache )
- Longest Common Prefix python题解