Chapter6 双指针,BFS和图论
双指针
1.日志统计 1238
经典的双指针模板题
所谓双指针其实就是针对多重循环的一种优化方式,缩小时间复杂度以确保不会TLE
循环的是一个时间段
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define x first #define y second using namespace std; typedef pair<int, int> PII; const int N = 1e5 + 10; int n, d, k; bool st[N]; int cnt[N]; PII rec[N]; int main() { cin >> n >> d >> k; for(int i = 0; i < n; i++ ) scanf("%d%d", &rec[i].x, &rec[i].y); sort(rec, rec + n); for(int i = 0, j = 0; i < n; i++ ) { int id = rec[i].y; cnt[id]++; while(rec[i].x - rec[j].x >= d) cnt[rec[j].y]--, j++;//优化循环 if(cnt[id] >= k) st[id] = true; } for(int i = 0; i <= N; i++ ) if(st[i]) cout << i << endl; return 0; }
BFS
1.献给阿尔吉侬的花束 1101
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define x first #define y second using namespace std; typedef pair<int, int> PII; const int N = 210; char a[N][N]; int dist[N][N]; int r, c; int bfs(PII start, PII end) { queue<PII> q; memset(dist, -1, sizeof dist); dist[start.x][start.y] = 0; q.push(start); int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; while(q.size()) { auto t = q.front(); q.pop(); for(int i = 0; i < 4; i++ ) { int x = t.x + dx[i], y = t.y + dy[i]; if(x < 0 || x >= r || y < 0 || y >= c) continue; if(dist[x][y] != -1) continue; if(a[x][y] == '#') continue; dist[x][y] = dist[t.x][t.y] + 1; if(end == make_pair(x, y)) return dist[x][y]; q.push({x, y}); } } return -1; } int main() { int T; cin >> T; while(T--) { PII start, end; cin >> r >> c; for(int i = 0; i < r; i++ ) cin >> a[i]; for(int i = 0; i < r; i++ ) for(int j = 0; j < c; j++ ) { if(a[i][j] == 'S') start = {i, j}; if(a[i][j] == 'E') end = {i, j}; } int distance = bfs(start, end); if(distance == -1) puts("oop!"); else cout << distance << endl; } return 0; }
图论
1.交换瓶子 1224
找原状态下有多少个环,单独的数自己成为一个环。每次交换同一个环内的数总环的数量增加1,所以想要达到题目要求的样子需要交换n - 初始环数
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1e4 + 10; bool st[N]; int n, b[N]; int main() { cin >> n; for(int i = 1; i <= n; i++ ) scanf("%d", b + i); int rnd = 0; for(int i = 1; i <= n; i++ ) if(!st[i]) { rnd++; for(int j = i; !st[j]; j = b[j]) st[j] = true; } cout << n - rnd << endl; return 0; }
DFS + Floodfill
红与黑 1113
dfs实现floodfill,依次遍历每个点的周围的点然后dfs邻近的点
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 25; char a[N][N]; bool st[N][N]; int w, h; int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; int bfs(int x, int y) { int cnt = 1; st[x][y] = true; for(int i = 0; i < 4; i++ ) { int m = x + dx[i], n = y + dy[i]; if(m < 0 || m >= h || n < 0 || n >= w) continue; if(a[m][n] == '#') continue; if(st[m][n]) continue; cnt += bfs(m, n); } return cnt; } int main() { while(cin >> w >> h, w || h)//w列 h行 { int x, y; for(int i = 0; i < h; i++ ) scanf("%s", a[i]); for(int i = 0; i < h; i++ ) for(int j = 0; j < w; j++ ) if(a[i][j] == '@') { x = i; y = j; } memset(st, 0, sizeof st); cout << bfs(x, y) << endl; } return 0; }
习题
1.完全二叉树的权值 1240 (双指针)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N = 1e5 + 10; int n, a[N]; int main() { cin >> n; for(int i = 1; i <= n; i++ ) scanf("%d", a + i); LL maxn = -1e18; int rnd; for(int i = 1, d = 1; i <= n; i *= 2, d++ ) { LL s = 0; for(int j = i; j <= n && j < i + (1 << d - 1); j++ ) s += a[j]; if(s > maxn) { rnd = d; maxn = s; } } cout << rnd << endl; return 0; }
2.地牢大师 1096
花束的推广,三维的bfs floodfill就可以解决,较简单
比较巧妙的是bfs函数中 ss 与 ee。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Point{ int x, y, z; }; const int N = 110; char g[N][N][N]; Point q[N * N * N]; int dist[N][N][N]; int L, R, C; int dx[6] = {0, 0, -1, 0, 1, 0}; int dy[6] = {0, 0, 0, 1, 0, -1}; int dz[6] = {1, -1, 0, 0, 0, 0}; int bfs(Point start, Point end) { memset(dist, -1, sizeof dist); dist[start.x][start.y][start.z] = 0; int ss = 0, ee = 0; q[0] = start;//根节点入列 while(ss <= ee) { auto t = q[ss++]; for(int i = 0; i < 6; i++ ) { int x = t.x + dx[i], y = t.y + dy[i], z = t.z + dz[i]; if(x < 0 || x >= L || y < 0 || y >= R || z < 0 || z >= C) continue; if(g[x][y][z] == '#') continue; if(dist[x][y][z] != -1) continue; dist[x][y][z] = dist[t.x][t.y][t.z] + 1; if(x == end.x && y == end.y && z == end.z) return dist[x][y][z]; q[++ee] = {x, y, z}; } } return -1; } int main() { while(cin >> L >> R >> C, L || R || C) { Point start, end; for(int i = 0; i < L; i++ ) for(int j = 0; j < R; j++ ) { scanf("%s", g[i][j]); for(int k = 0; k < C; k++ ) { if(g[i][j][k] == 'S') start = {i, j, k}; if(g[i][j][k] == 'E') end = {i, j, k}; } } int distance = bfs(start, end); if(distance == -1) printf("Trapped!\n"); else printf("Escaped in %d minute(s).\n", distance); } return 0; }
3.全球变暖 1233(bfs floodfill dfs)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define x first #define y second using namespace std; typedef pair<int, int> PII; const int N = 1010; int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; char g[N][N]; bool st[N][N]; PII q[N * N]; int n; void bfs(int x, int y, int &total, int &bound) { st[x][y] = true; q[0] = {x, y}; int ss = 0, ee = 0; while(ss <= ee) { PII t = q[ss++]; total++; bool is_bound = false; for(int i = 0; i < 4; i++ ) { int pp = t.x + dx[i], qq = t.y + dy[i]; if(pp < 0 || pp >= n || qq < 0 || qq >= n) continue; if(st[pp][qq]) continue; if(g[pp][qq] == '.') { is_bound = true; continue; } q[++ee] = {pp, qq}; st[pp][qq] = true; } if(is_bound) bound++; } } int main() { scanf("%d", &n); for(int i = 0; i < n; i++ ) scanf("%s", g[i]); int cnt = 0; for(int i = 0; i < n; i++ ) for(int j = 0; j < n; j++ ) if(g[i][j] == '#' && !st[i][j]) { int total = 0, bound = 0; bfs(i, j, total, bound); if(total == bound) cnt++; } cout << cnt << endl; return 0; }
4.大臣的旅费 1207(待补充单链表法)
找树的直径:
任取一点x,找距离x最远的点y
再找距离y最远的点z
yz距离即为数的直径
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int N = 1e5 + 10; struct Node { int id, w; }; int dist[N]; int n; vector<Node> h[N]; void dfs(int u, int father, int distance) { dist[u] = distance; for(auto node : h[u]) if(node.id != father)//防止dfs回去 dfs(node.id, u, node.w + distance); } int main() { cin >> n; for(int i = 0; i < n - 1; i++ ) { int a, b, c; scanf("%d%d%d", &a, &b, &c); h[a].push_back({b, c}); h[b].push_back({a, c}); } dfs(1, -1, 0); int u = 1; for(int i = 1; i <= n; i++ ) if(dist[i] > dist[u]) u = i; dfs(u, -1, 0);//无父节点,形参二任取,取-1 for(int i = 1; i <= n; i++ ) if(dist[i] > dist[u]) u = i; int s = dist[u]; printf("%lld\n", s * 10 + s * (s + 1ll) / 2); return 0; }
单链表
1.单链表 826
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 1e5 + 10; int head, e[N], ne[N], idx; //链表初始化 void init() { head = -1; idx = 0; } void add_head(int x) { e[idx] = x; ne[idx] = head; head = idx++; } void add_k(int k, int x) { e[idx] = x; ne[idx] = ne[k]; ne[k] = idx ++ ; } void remove(int k) { ne[k] = ne[ne[k]]; } int main() { init(); int m; cin >> m; while (m -- ) { char op; int k, x; cin >> op; if (op == 'H') { cin >> x; add_head(x); } else if (op == 'I') { cin >> k >> x; add_k(k - 1, x); } else { cin >> k; if (!k) head = ne[head]; else remove(k - 1); } } for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' '; cout << endl; return 0; }
来源:https://www.cnblogs.com/scl0725/p/12491955.html