int distance = d[t]; if(t == end) return distance; // 状态转移 int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; int k = t.find('x'); int x = k / 3, y = k % 3; for (int i = 0; i < 4; i++){ int a = x + dx[i], b = y + dy[i]; if( a >= 0 && a < 3 && b >= 0 && b<3){ swap(t[k], t[3 * a + b]); if(!d.count(t)) { d[t] = distance + 1; q.push(t); } swap(t[k], t[3 * a + b]); } } } return-1; }
intmain(){ string start; for (int i = 0; i < 9; ++i) { char c; cin >> c; start += c; } cout << bfs(start) << endl;
constint N = 1010; typedef pair<int, int> PII; int n, m; char g[N][N]; int d[N][N];
voidbfs(){ memset(d, -1, sizeof d);
queue<PII> q; for (int i = 0; i < n;i++) for (int j = 0; j < m;j++) if (g[i][j] == '1') { q.push({i, j}); d[i][j] = 0; }
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; while(q.size()) { auto t = q.front(); q.pop(); int a = t.first; int b = t.second; for (int i = 0; i < 4;i++) { int x = a + dx[i], y = b + dy[i]; if(x >= 0 && x < n && y >=0 && y < m && d[x][y] == -1) { d[x][y] = d[a][b] + 1; q.push({x, y}); } } } } // 3 4 // 0001 // 0011 // 0110
// 3 2 1 0 // 2 1 0 0 // 1 0 0 1 intmain(){ cin >> n >> m; for (int i = 0; i < n; i++) cin >> g[i]; // scanf("%s",g[i]); bfs(); for (int i = 0; i < n;i++){ for (int j = 0; j < m;j++) cout << d[i][j]<< ' '; puts(""); }
constint N = 100010, M = N * 2; int n, m; // n个链表头(相当于n个head) e是结点值 ne是next指针 int h[N], e[M], ne[M],idx; bool st[N]; // a 插向 b voidadd(int a,int b){ e[idx] = b, ne[idx] = h[a], h[a] = idx++; } memset(h,-1,sizeof h);
booltopsort(){ int hh = 0, tt = -1; for (int i = 1; i <= n;i++) if(d[i]==0) // 入度为0的点入队 q[++tt] = i; while(hh <= tt) { auto t = q[hh++]; for (int i = h[t]; i != -1; i = ne[i]) { int j = e[i]; d[j]--; if (d[j] == 0) q[++tt] = j; } } return tt == n - 1; // 一共进了n个点 是有向无环图 }
intmain(){ cin >> n >> m; memset(h, -1, sizeof h); for (int i = 0; i < m;i++){ int a, b; cin >> a >> b; add(a, b); d[b]++; } if(topsort()) { for (int i = 0; i < n;i++) cout << q[i] << ' '; puts(""); } elseputs("-1"); return0; }
最短路问题
稠密图用 dijkstra(临接矩阵)
稀疏用堆优化版(临接表)
不超过 k 条边 Bellman-Ford
难点在建图和抽象具体问题 不在于证明
Dijkstra(朴素 稠密图)
memset 说明 🎇
如果用 memset(a,1,20);(实际上与 memset(a,1,5*sizeof(int))结果是一样的)就是对 a 指向的内存的 20 个字节进行赋值,每个都用 ASCⅡ 为 1 的字符去填充,转为二进制后,1 就是 00000001,占一个字节。一个 INT 元素是 4 字节,合一起是 0000 0001,0000 0001,0000 0001,0000 0001,转化成十六进制就是 0x01010101,就等于 16843009,就完成了对一个 INT 元素的赋值了。
#include<cstring> #include<iostream> #include<algorithm> // #include <bits/stdc++.h> usingnamespace std; constint N = 510; int n, m; int g[N][N]; int dist[N]; // 1到各个点的距离 bool st[N]; // 各个点是否确定
intmain(){ //cout << 0x3f3f3f3f << endl; cin >> n >> m; memset(g, 0x3f, sizeof g); while(m--){ int a, b, c; cin >> a >> b >> c; g[a][b] = min(g[a][b], c); } int t = dijkstra(); cout << t << endl; return0; }
while(heap.size()) { auto t = heap.top(); heap.pop();
int ver = t.second, dstance = t.first; // 编号 和 距离 if(st[ver]) continue; // 若出现则跳过 // 用 t 更新其他点 st[ver] = true; for (int i = h[ver]; i != -1;i = ne[i]) { int j = e[i]; if(dist[j] > dstance + w[i]) { dist[j] = dstance + w[i]; heap.push({dist[j], j}); } } } if(dist[n] == 0x3f3f3f3f) return-1; return dist[n]; }
intmain(){ cin >> n >> m; memset(h,-1,sizeof h); while(m--){ int a, b, c; cin >> a >> b >> c; add(a, b, c); } int t = dijkstra(); cout << t << endl; return0; }
for (int i = 0; i < k; i ++ ) { memcpy(backup, dist, sizeof dist); // 备份上一次数据 防止数据串联 for (int j = 0; j < m; j++) { int a = edges[j].a, b = edges[j].b, w = edges[j].w; dist[b] = min(dist[b], backup[a] + w); } } if (dist[n] > 0x3f3f3f3f / 2) return-1; // 负权边可能更新dist[n] < INF return dist[n]; } intmain(){ // cout << 0x3f3f3f3f; cin >> n >> m >> k;
for (int i = 0; i < m; i++) { int a, b, w; cin >> a >> b >> w; edges[i] = {a, b, w}; } int t = bellman_ford(); if(t == -1 && dist[n] != -1) puts("impossible"); // && 解决 1 -> 2 = -1情况 else cout << t << endl; return0; }
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 510, INF = 0x3f3f3f3f;
int n, m; int g[N][N]; int dist[N]; bool st[N];
int prim(){ memset(dist, 0x3f, sizeof dist); int res = 0; 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;
voidkruskal() { sort(edge, edge + m); // 从小到大排序 for(int i = 1; i <= n; i ++) p[i] = i; // 并查集初始化
int res = 0, cnt = 0; for(int i = 0; i < m; i ++) { int a = edge[i].a, b = edge[i].b, w = edge[i].w; a = find(a), b = find(b); if(a != b) { p[a] = b; res += w; cnt ++; } } // cout << cnt; if(cnt == n - 1) cout << res << endl; // 存在最小生成树cnt == n - 1!!! else cout << "impossible" << endl; }
intmain() {
cin >> n >> m; for(int i = 0; i < m; i ++) cin >> edge[i].a >> edge[i].b >> edge[i].w;