01 bfs
UVA11573 Ocean Currents
分析:
题中给了两种移动方式,一种是沿着洋流的方向移动,不需要消耗能量,不沿着洋流走需要消耗1能量,此类按照普通的bfs不能保证队列前面的一定是当前消耗能量最少的情况。
正确做法是利用双端队列,不消耗能量就从队首入队,消耗能量就从队尾入队,这样就能保证队列前面的一定是当前消耗能量最小的
AC代码:
#include <bits/stdc++.h> using namespace std; int n, m; char ch[1005][1005]; int ans; int k; int rs, cs, rd, cd; struct node { int x, y, t; }; int vis[1005][1005]; int mov[8][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}}; bool judge(struct node no) { if(no.x < 1 || no.x > n || no.y < 1 || no.y > n) return true; return false; } void bfs(int rs, int cs, int rd, int cd) { memset(vis, 0x3f3f, sizeof(vis)); ans = 0; deque<node> q; node now, next; vis[rs][cs] = 0; now.x = rs, now.y = cs, now.t = 0; q.push_front(now); while(!q.empty()) { now = q.front(); q.pop_front(); if(now.x == rd && now.y == cd) { ans = now.t; return ; } for(int i = 0; i < 8; ++i) { next.x = now.x + mov[i][0]; next.y = now.y + mov[i][1]; if(judge(next)) continue; if(ch[now.x][now.y] - '0' == i) { next.t = now.t; if(vis[next.x][next.y] > next.t) { vis[next.x][next.y] = next.t; q.push_front(next); } } else { next.t = now.t + 1; if(vis[next.x][next.y] > next.t) { vis[next.x][next.y] = next.t; q.push_back(next); } } } } } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) scanf("%s", ch[i] + 1); scanf("%d", &k); while(k--) { scanf("%d%d%d%d", &rs, &cs, &rd, &cd); bfs(rs, cs, rd, cd); printf("%d\n", ans); } return 0; }
CF590C Three States
分析:
这个题与和上一个不同于不是单一起点和单一终点
这个题需要以每个国家的任意一格为起点,对整张图跑一遍01BFS,就得到了三个国家到所有各自的距离。在这三个国家都跑完之后就遍历一遍,取min即可
dis[a][i][j]记录点i,j到国家a的距离,最后遍历一遍dis数组即可。
AC代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n, m; char ch[1005][1005]; //bool vis[1005][1005]; int dis[4][1005][1005]; int mov[][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; #define pa pair<int, int> #define x first #define y second bool judge(int x, int y) { if(x < 1 || x > n || y < 1 || y > m || ch[x][y] == '#' ) return true; return false; } void bfs(int a) { deque<pa> q; //memset(vis, 0,sizeof(vis)); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(ch[i][j] - '0' == a) { q.push_back({i, j}); dis[a][i][j] = 0; //vis[i][j] = 1; } } } while(!q.empty()) { pa now = q.front(); q.pop_front(); for(int i = 0; i < 4; ++i) { int fx = now.x + mov[i][0]; int fy = now.y + mov[i][1]; if(judge(fx, fy)) continue; //vis[fx][fy] = 1; int k = (ch[fx][fy] == '.'); if(dis[a][fx][fy] > dis[a][now.x][now.y] + k) { dis[a][fx][fy] = dis[a][now.x][now.y] + k; if(k) q.push_back({fx, fy}); else q.push_front({fx, fy}); } } } } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) scanf("%s", ch[i] + 1); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { for(int k = 1; k <= 3; ++k) dis[k][i][j] = 1e8; } } bfs(1), bfs(2), bfs(3); int ans = 1e8; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(ch[i][j] == '#') continue; int k = 0; if(ch[i][j] == '.') k = 2; //一个点只需要铺一次,所以是.的话需要-2 ans = min(ans, dis[1][i][j] + dis[2][i][j] + dis[3][i][j] - k); } } if(ans == 1e8) printf("-1\n"); else printf("%d\n", ans); return 0; }