NOIP2011 Mayan游戏 - 搜索

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Fantasy_World/article/details/81876425

一个有效的剪枝是排除等效冗沉,当两种操作形成等效效果时不重复搜索
若有两个块,那么左边的右移和右边的左移是等效的,由于题意认为右移优先于左移,所以这种情况只取右移,而一个块左边是空的时候则要尝试左移

在回溯法“还原”的时候,可以先复制出来局面,在函数里开数组(别用全局的,要保存多个局面),然后复制回去
但仔细想想不需要再复制回去了,大不了每次都开个数组,直接当dfs的参数传下去,然后每次dfs用参数表里的数组就是了

因为一开始我没想到那个“左右移等效”,为了不让一个块来回左右走许多次,我记了个lasti 表示上一次移动的块的坐标,但是lasti初始值应为-1 因为 0,0 也是合法的坐标,并且lasti应该在参数表里而不是全局定义

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100;
int g[MAXN][MAXN], n, h[MAXN], cg[10][10], fg[10][10],ans[10][10],sum[10];
bool flg = false, now_flg;
void copy(int a[5][7]) {
    for(int i=0; i<5; i++) 
        for(int j=0; j<7; j++)
            a[i][j] = g[i][j];
}
void reco(int a[5][7]) {
    for(int i=0; i<5; i++)
        for(int j=0; j<7; j++)
            g[i][j] = a[i][j];
}
void tran() {
    for(int i=0; i<7; i++) 
        for(int j=0; j<=2; j++) 
            if(g[j][i] == g[j+1][i] && g[j][i] == g[j+2][i] && g[j+1][i] == g[j+2][i] && g[j][i]) {
                now_flg = true;
                for(int k=0; k<=2; k++) 
                    fg[j+k][i] = 1;
            }
}
void vert() {
    for(int i=0; i<5; i++) 
        for(int j=0; j<=4; j++) 
            if(g[i][j] == g[i][j+1] && g[i][j] == g[i][j+2] && g[i][j+1] == g[i][j+2] && g[i][j]) {
                now_flg = true;
                for(int k=0; k<=2; k++) 
                    fg[i][j+k] = 1;
            }
}
void corr() {
    for(int i=0; i<5; i++) 
        for(int j=0; j<7; j++) 
            if(fg[i][j])
                g[i][j] = 0;
    for(int i=0; i<5; i++) {
        for(int j=0; j<7; j++) 
            if(!g[i][j]) 
                sum[j] = sum[j-1] + 1;
            else sum[j] = sum[j-1];
        for(int j=0; j<7; j++) 
            if(g[i][j]) {
                g[i][j-sum[j]] = g[i][j];
                if(sum[j]) g[i][j] = 0;
            }
    }
    memset(fg, 0, sizeof(fg));
}
void modify(int x, int y, int mx) {
    corr();
    do {
        now_flg = false;
        tran();
        vert();
        corr(); 
    } while(now_flg);
}
bool check() {
    int total = 0;
    for(int i=0; i<7; i++) 
        for(int j=0; j<5; j++)
            total += g[i][j];
    if(!total) 
        return true;
    else return false;
}
void dfs(int x, int lasti, int lastj) {
    if(x == n + 1) {
        if(check()) {
            flg = true;
            return;
        }
        return;
    }
    for(int i=0; i<5; i++) 
        for(int j=0; j<7; j++) {
            if(!g[i][j] || (i == lasti && j == lastj))
                continue;
            if(flg) return;
            int tem[5][7];
            if(i != 4) {
                copy(tem);
                swap(g[i][j], g[i+1][j]);   
                modify(i, j, i+1);
                ans[x][0] = i, ans[x][1] = j, ans[x][2] = 1;
                dfs(x+1, i, j);
                if(flg) return;
                reco(tem);
            }
            if(i != 0 && g[i-1][j] == 0) {
                copy(tem);
                swap(g[i][j], g[i-1][j]);
                modify(i, j, i-1);
                ans[x][0] = i, ans[x][1] = j, ans[x][2] = -1;
                dfs(x+1, i, j);
                if(flg) return;
                reco(tem);
            }
        }
}
int main() {
    cin >> n;
    for(int i=0; i<5; i++) {
        int noww = 0;
        int x;
        do{
            scanf("%d", &x);
            g[i][noww++] = x;
        }while(x != 0);
    }
    dfs(1, -1, -1); 
    if(flg)
        for(int i=1; i<=n; i++) 
            printf("%d %d %d\n", ans[i][0], ans[i][1], ans[i][2]);
    else printf("-1");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Fantasy_World/article/details/81876425