搜索

E - The Morning after Halloween

 UVA - 1601

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
", 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
", dfs(1, n, 0));
}
原文地址:https://www.cnblogs.com/downrainsun/p/10449537.html