搜索
E - The Morning after Halloween
https://blog.csdn.net/qq_29169749/article/details/51420097
这里有双向bfs板,注意双向是搜索一层,而不是一个点。
这个提的意思是有小于三个小鬼,编号abc,他们要到ABC去,然后求最少的步数,不能够两个小鬼到一个点,也不可以一步是两个小鬼互交换位置。
首先这个图不连通的地方很多,我们可以把它提出来,编号,自己建一个树来记录小鬼可以移动的 位置。小鬼可以不动和上下左右动(重点看一下那个提出来建图的过程)
然后提出来之后进行bfs来求出小鬼最小的移动次数。如果没有三个小鬼就自己在添到三个小鬼,要不然要写三个bfs来分别求一个,两个,三个小鬼的情况,然后把那个小鬼连的边就是终点,不影响结果。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cstdlib> #include<cctype> using namespace std; const int maxm = 20; const int maxm1 = 150; const int dx[] = {-1,1,0,0,0}; const int dy[] = {0,0,-1,1,0}; char maze[maxm][maxm]; int n, m, k; int G[maxm1][5]; int deg[maxm1]; int cnt; int s[3], e[3]; struct node{ int a, b, c; int steps; }; bool check(int a, int b, int ea, int eb){ return ea == eb || (a == eb && b == ea); } queue<node> q; int visit[maxm1][maxm1][maxm1]; int bfs(){ memset(visit,0,sizeof(visit)); while(!q.empty()) q.pop(); node start, pre, temp; start.a = s[0], start.b = s[1], start.c = s[2]; start.steps = 0; q.push(start); while(!q.empty()){ pre = q.front(); q.pop(); if(pre.a == e[0] && pre.b == e[1] && pre.c == e[2]) return pre.steps; for(int i = 0; i < deg[pre.a]; i++) { int na = G[pre.a][i]; for(int j = 0; j < deg[pre.b]; j++) { int nb = G[pre.b][j]; if(check(pre.a, pre.b, na, nb)) continue; for(int k = 0; k < deg[pre.c]; k++){ int nc = G[pre.c][k]; if(check(pre.a,pre.c,na,nc) || check(pre.b,pre.c,nb,nc)) continue; temp.a = na; temp.b = nb; temp.c = nc; temp.steps = pre.steps + 1; if(!visit[na][nb][nc]) q.push(temp); visit[na][nb][nc] = 1; } } } } return -1; } int main() { while(~scanf("%d%d%d", &n, &m, &k)){ if(n == 0 && m == 0 && k == 0) break; getchar(); for(int i = 0; i < m; i++) fgets(maze[i], 20, stdin); cnt = 0; int x[maxm1], y[maxm1]; int id[maxm1][maxm1]; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ if(maze[i][j] != '#'){ x[cnt] = i; y[cnt] = j; id[i][j] = cnt; if(islower(maze[i][j])) s[maze[i][j] - 'a'] = cnt; if(isupper(maze[i][j])) e[maze[i][j] - 'A'] = cnt; cnt++; } } } for(int i = 0; i < cnt; i++){ deg[i] = 0; for(int j = 0; j < 5; j++){ int tx = x[i] + dx[j], ty = y[i] + dy[j]; if(maze[tx][ty] != '#') { G[i][deg[i]++] = id[tx][ty]; } } } if (k <= 2){deg[cnt] = 1; G[cnt][0] = cnt; s[2] = e[2] = cnt++;} if (k <= 1){deg[cnt] = 1; G[cnt][0] = cnt; s[1] = e[1] = cnt++;} printf("%d\n", bfs()); } return 0; }
http://codeforces.com/contest/448/problem/C dfs分治
刷围墙
每个板子宽度相同,高度不同,刷一次可以横着刷一行或者一竖(宽度为一)
https://www.cnblogs.com/fu3638/p/9892300.html 分治法dfs
https://blog.csdn.net/qcwdytx/article/details/38019303 dp法
#include<bits/stdc++.h> using namespace std; const int maxm = 1e5 + 5; const int inf = 1e9 + 7; int n; int a[maxm]; int dfs(int l, int r, int h) { if(l == r) return 1; int hh = inf; for(int i = l; i <= r; i++) { hh = min(hh, a[i]); } int sum = hh - h; for(int i = l; i <= r; i++) { if(a[i] == hh) continue; int j = i; while(a[j + 1] > hh && j + 1 <= r) j++; sum += dfs(i, j, hh); i = j; } return min(r - l + 1, sum); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); printf("%d\n", dfs(1, n, 0)); }