剪格子(迭代加深搜索)

剪格子(迭代加深搜索)_第1张图片
这题数据比较水,直接暴力是能过的,但是却可以做的更优。
<1>有两个行之有效且易于运用的剪枝。

  1. 当目前搜索的和大于总和的1/2时,回溯
  2. 当目前搜索步数大于已知最优解时,回溯
这里写代码片#include
#include
using namespace std;

const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};

int a[20][20];
int f[20][20];
int dep, sum, n, m, ans = 0;

void dfs(int de, int x, int y, int k){
    if(k + k == sum) {
        ans = de;//更新已知最优解
    }
    if(ans && de > ans || k * 2 > sum){//符合上面两点就回溯
        return;
    }
    for(int i = 0; i < 4; i++){
        int xx = x + dx[i];
        int yy = y + dy[i];
        if(xx < 1 || yy < 1 || xx > n || yy > m || f[xx][yy] == 1) continue;
        f[xx][yy] = 1;
        dfs(de + 1, xx, yy, k + a[xx][yy]);
        f[xx][yy] = 0;
    }
}

int main(){
    scanf("%d%d", &m, &n);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &a[i][j]);
            sum += a[i][j];
        }
    }
    dfs(1, 1, 1, a[1][1]);  
    printf("%d\n", ans);
    return 0;
}

<2>迭代加深
这两点优化可以让程序比暴力提高成千上万倍速度。但是还有一些不可避免的浪费。比如说,假设正解是x,那么这两点不可避免的回搜索到第x层,x+1层……我们知道搜索依托的是树形结构,树的每一层之间的差距很大,我们搜索x+1层可能要消耗第x层几倍的时间。
我们可以用迭代加深搜索。枚举递归深度,如果在当前深度可以找到答案的话就直接输出。
枚举深度的时候,会重复搜索原来的深度,比如深度枚举到4的时候,必然会走一遍深度为3的路子。但是因为每层之间节点数目差距较大,可以忽略。
所以,看起来迭代加深是集合了深搜与广搜的优点的

#include
#include
using namespace std;

const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};

int a[20][20];
int f[20][20];
int dep, sum, n, m;

int dfs(int de, int x, int y, int k){
    if(k + k == sum) {
        return 1;
    }
    if(de > dep || k * 2 > sum){
        return 0;
    }
    for(int i = 0; i < 4; i++){
        int xx = x + dx[i];
        int yy = y + dy[i];
        if(xx < 1 || yy < 1 || xx > n || yy > m || f[xx][yy] == 1) continue;
        f[xx][yy] = 1;
        if(dfs(de + 1, xx, yy, k + a[x][y])) return 1;
        f[xx][yy] = 0;
    }
    return 0;
}

int main(){
    scanf("%d%d", &m, &n);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &a[i][j]);
            sum += a[i][j];
        }
    }
    for(dep = 1; dep < n * m; dep++){
        memset(f, 0, sizeof(f));
        if(dfs(1, 1, 1, 0)){
            printf("%d\n", dep);
            break;  
        } 
    }
    if(dep == n*m) puts("0");
    return 0;
}

你可能感兴趣的:(搜索,蓝桥)