voidbfs(int a, int b) { que[++tt] = {a, b}; dist[a][b] = 0; while (hh <= tt) { PII t = que[hh++]; int x = t.first, y = t.second; for (int i = 0; i < 4; i++) { int xx = x + dx[i], yy = y + dy[i]; if (mp[xx][yy] == 0 && xx >= 1 && xx <= n && yy >= 1 && yy <= m) { dist[xx][yy] = dist[x][y] + 1; mp[xx][yy] = 1; que[++tt] = {xx, yy}; } } } }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; memset(dist, -1, sizeof dist); // 初始化距离数组为-1,如果某个位置dist仍为-1,表示该位置未被访问过 for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> mp[i][j]; bfs(1, 1); cout << dist[n][m]; }
八数码
题干
在一个 的网格中, 这 个数字和一个 x 恰好不重不漏地分布在这 的网格中。
例如:
1 2 3
1 2 3 x 4 6 7 5 8
在游戏过程中,可以把 x 与其上、下、左、右四个方向之一的数字交换(如果存在)。
我们的目的是通过交换,使得网格变为如下排列(称为正确排列):
1 2 3
1 2 3 4 5 6 7 8 x
例如,示例中图形就可以通过让 x 先后与右、下、右三个方向的数字交换成功得到正确排列。
交换过程如下:
1 2 3
1 2 3 1 2 3 1 2 3 1 2 3 x 4 6 4 x 6 4 5 6 4 5 6 7 5 8 7 5 8 7 x 8 7 8 x
现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。
输入格式
输入占一行,将 的初始网格描绘出来。
例如,如果初始网格如下所示:
1 2 3
1 2 3 x 4 6 7 5 8
则输入为:1 2 3 x 4 6 7 5 8
输出格式
输出占一行,包含一个整数,表示最少交换次数。
如果不存在解决方案,则输出 。
输入样例
1
2 3 4 1 5 x 7 6 8
输出样例
1
19
思路分析
本题考查 BFS 在状态空间搜索中的应用。我们可以将每一个网格状态视为图中的一个节点,通过交换 x 与相邻数字来生成新的状态节点。BFS 能够帮助我们找到从初始状态到目标状态的最短路径。
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 10;
int h[N], e[N], ne[N], dist[N], idx = 1, n, m; int que[N], hh = 1, tt = 0;
voidadd(int a, int b) { e[idx] = b; ne[idx] = h[a]; h[a] = idx++; }
voidbfs(int u) { que[++tt] = u; dist[u] = 0; while (hh <= tt) { int t = que[hh++]; for (int i = h[t]; i; i = ne[i]) { int j = e[i]; if (dist[j] == -1) { dist[j] = dist[t] + 1; que[++tt] = j; } } } }
intmain() { cin >> n >> m; memset(dist, -1, sizeof dist); for (int i = 1; i <= m; i++) { int a, b; cin >> a >> b; add(a, b); } bfs(1); cout << dist[n]; }
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 10;
bool st[N]; int h[N], e[N], ne[N], in_degree[N], idx = 1; int n, m;
int que[N], hh = 1, tt = 0;
voidadd(int a, int b) { e[idx] = b; ne[idx] = h[a]; h[a] = idx++; }
voidtop_sort() { // 初始化队列,将所有入度为0的点入队 for (int i = 1; i <= n; i++) if (!in_degree[i]) que[++tt] = i; while (hh <= tt) { int t = que[hh++]; for (int i = h[t]; i; i = ne[i]) { int j = e[i]; st[j] = true; in_degree[j]--; // 每遍历到一个点,就将其入度减1 if (!in_degree[j]) que[++tt] = j; // 如果入度变为0,就将其入队 } } }
intmain() { cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b; cin >> a >> b; add(a, b); in_degree[b] += 1; } top_sort(); if (tt == n) for (int i = 1; i <= n; i++) cout << que[i] << ' '; else cout << -1; }
int n, m, idx = 1; int e[N], ne[N], h[N], edge[N], dist[N]; bool st[N]; priority_queue<PII, vector<PII>, greater<PII>> heap;
voidadd(int a, int b, int c) { e[idx] = b; ne[idx] = h[a]; h[a] = idx; edge[idx] = c; idx++; }
intdijkstra() { memset(dist, 0x3f, sizeof dist); dist[1] = 0; heap.push({0, 1}); while (heap.size()) { auto t = heap.top(); heap.pop(); int distance = t.first, ver = t.second; if (st[ver]) continue; st[ver] = true; for (int i = h[ver]; i; i = ne[i]) { int j = e[i]; if (!st[j]) { dist[j] = min(dist[j], distance + edge[i]); heap.push({dist[j], j}); } } } if (dist[n] > 0x3f3f3f3f / 2) return-1; return dist[n]; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; memset(edge, 0x3f, sizeof edge); for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } cout << dijkstra(); }
#include<bits/stdc++.h> usingnamespace std; constint N = 1e5 + 10;
int h[N], e[N], ne[N], edge[N], idx = 1; int n, m; int dist[N];
int que[N], hh = 1, tt = 0; bool st[N];
voidadd(int a, int b, int c) { e[idx] = b; ne[idx] = h[a]; h[a] = idx; edge[idx] = c; idx++; }
voidspfa(int u) { memset(dist, 0x3f3f3f3f, sizeof dist); dist[u] = 0; que[++tt] = u; st[u] = true; while (hh <= tt) { int t = que[hh++]; st[t] = false; // 出队时马上标记为不在队列中 for (int i = h[t]; i; i = ne[i]) { int j = e[i]; if (dist[j] > dist[t] + edge[i]) { dist[j] = dist[t] + edge[i]; if (!st[j]) { que[++tt] = j; st[j] = true; } } } } if (dist[n] > 0x3f3f3f3f / 2) cout << "impossible"; else cout << dist[n]; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } spfa(1); return0; }
#include<bits/stdc++.h> usingnamespace std; constint N = 2010, M = 10010;
int h[N], e[M], ne[M], edge[M], idx = 1; int n, m; int dist[N], cnt[N];
queue<int> q; bool st[N];
voidadd(int a, int b, int c) { e[idx] = b; ne[idx] = h[a]; h[a] = idx; edge[idx] = c; idx++; }
boolspfa() { for (int i = 1; i <= n; i++) { q.push(i); st[i] = true; } while (!q.empty()) { int t = q.front(); q.pop(); st[t] = false; for (int i = h[t]; i; i = ne[i]) { int j = e[i]; if (dist[j] > dist[t] + edge[i]) { dist[j] = dist[t] + edge[i]; cnt[j] = cnt[t] + 1; if (cnt[j] >= n) returntrue; if (!st[j]) { q.push(j); st[j] = true; } } } } returnfalse; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } if (spfa()) cout << "Yes" << '\n'; else cout << "No" << '\n'; return0; }
#include<bits/stdc++.h> usingnamespace std; constint N = 510;
int n, m; int dist[N], edge[N][N]; bool st[N];
intprim() { int res = 0; memset(dist, 0x3f, sizeof dist); for (int i = 0; i < n; i++) { int t = -1; for (int j = 1; j <= n; j++) if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j; // 选出未加入最小生成树的点中距离最小的点
st[t] = true; // 将该点加入最小生成树
if (!i) dist[t] = 0; // 如果是第一个点,则将距离设为0
if (i && dist[t] > 0x3f3f3f3f / 2) return dist[t]; // 如果不是第一个点且距离为大数,说明不是连通图,不存在最小生成树
intmain() { // ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; memset(edge, 0x3f, sizeof edge); for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; edge[a][b] = edge[b][a] = min(edge[a][b], c); } int u = prim(); if (u > 0x3f3f3f3f / 2) cout << "impossible" << '\n'; else cout << u; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= m; i++) cin >> edge[i].st >> edge[i].ed >> edge[i].len; for (int i = 1; i <= n; i++) p[i] = i; sort(edge + 1, edge + 1 + m); int cnt = 0, res = 0; // cnt记录已经加入最小生成树的边数 // res记录最小生成树的边权和 for (int i = 1; i <= m; i++) { int st = edge[i].st, ed = edge[i].ed, len = edge[i].len; st = find(st), ed = find(ed); if (st != ed) { res += len; cnt++; p[st] = ed; } // 如果两个节点不在同一个集合中,则将它们合并 } if (cnt < n - 1) cout << "impossible" << '\n'; else cout << res; }
#include<bits/stdc++.h> usingnamespace std; typedef pair<int, int> PII; constint N = 1e5 + 10, M = 2e5 + 10;
int n, m; int h[N], e[M], ne[M], idx = 1; int st[N]; // st数组存颜色,0代表未染色,1代表颜色1,2代表颜色2 // 3 - color表示另一种颜色 queue<PII> q;
voidadd(int a, int b) { e[idx] = b; ne[idx] = h[a]; h[a] = idx++; }
boolbfs(int u) { st[u] = 1; q.push({u, st[u]}); while (!q.empty()) { PII t = q.front(); q.pop(); int point = t.first, color = t.second; for (int i = h[point]; i; i = ne[i]) { int j = e[i]; if (!st[j]) { st[j] = 3 - color; q.push({j, st[j]}); } elseif (st[j] == color) returnfalse; // 如果j点没染色,就染成相反颜色 // 如果j点已经染色且颜色与当前点相同,则说明不是二分图 } } returntrue; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b; cin >> a >> b; add(a, b), add(b, a); } for (int i = 1; i <= n; i++) { if (!st[i]) if (!bfs(i)) { cout << "No" << '\n'; return0; } } cout << "Yes" << '\n'; return0; }
#include<bits/stdc++.h> usingnamespace std; typedef pair<int, int> PII; constint N = 1e5 + 10, M = 2e5 + 10;
int n, m; int h[N], e[M], ne[M], idx = 1; int st[N]; queue<PII> q;
voidadd(int a, int b) { e[idx] = b; ne[idx] = h[a]; h[a] = idx++; }
booldfs(int u, int color) { st[u] = color; // 将当前节点染成指定颜色 for (int i = h[u]; i; i = ne[i]) { int j = e[i]; if (st[j] == color) returnfalse; // 如果相邻节点颜色与当前节点相同,则说明不是二分图 elseif (!st[j]) if (!dfs(j, 3 - color)) returnfalse; // 如果相邻节点未染色,则将对该节点和相反颜色进行dfs } returntrue; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b; cin >> a >> b; add(a, b), add(b, a); } for (int i = 1; i <= n; i++) { if (!st[i]) if (!dfs(i, 1)) { cout << "No" << '\n'; return0; } } cout << "Yes" << '\n'; return0; }
#include<bits/stdc++.h> usingnamespace std; typedef pair<int, int> PII; constint N = 510, M = 1e5 + 10;
int n1, n2, m; int h[N], e[M], ne[M], idx = 1; // 邻接表存的值只有女生 bool st[N]; // st数组用来标记每一轮女生是否被访问过 // 它的意义是防止同一轮换对象时,同一个女生一直被重复访问,导致死循环 int match[N]; // match数组用来存每个女生当前匹配的男生
voidadd(int a, int b) { e[idx] = b; ne[idx] = h[a]; h[a] = idx++; }
boolfind(int x) { for (int i = h[x]; i; i = ne[i]) { int j = e[i]; // 遍历男生x能配对的女生j if (!st[j]) { st[j] = true; // 如果女生j该轮还没被访问过,则标记为已访问 if (!match[j] || find(match[j])) { match[j] = x; returntrue; // 如果女生j没有对象,或者她的对象能换人成功 // 则将女生j与男生x配对成功,返回true } } } returnfalse; }
intmain() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n1 >> n2 >> m; while (m--) { int u, v; cin >> u >> v; add(u, v); // 虽然是无向图,但由于我们只访问男生,因此只需要存男生到女生的边 } int res = 0; for (int i = 1; i <= n1; i++) { memset(st, 0, sizeof st); // 由于st表示每一轮的女生状态,下一轮时需要将st数组清空,参考上述例子,如果不清空的话,男2就无法访问女1 if (find(i)) res++; } cout << res << '\n'; }