HDU - 2234 - 无题 (DFS + 剪枝)

无题

题目链接: 无题I

题意

在一个4*4的矩阵中分别有4个1,4个2,4个3和4个4分别表示4种不同的东西,每一步小A可以把同一行的4个数往左移或者往右移一步或者把同一列的4个数字往上移或者往下移一步(1,2,3,4往左移后是2,3,4,1),小A现在想知道进过最少的几步移动可以将矩阵的每行上的4个数字都一样或者每列上的4个数字都一样。


思路

直接暴力DFS即可。但是适当的剪枝可以大大优化算法的复杂性,可以说是运用了简单的A*技巧吧。

就单单加了一个get_h函数后,就可以剪掉大部分无用的搜索了


代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back

typedef double db;
typedef long long ll;
const int MAXN = (int)1e6+7;
const int INF = (int)0x3f3f3f3f;

int pic[6][6];
int res;

bool check() {
    int flag = 0;
    rep(i,1,4) {
        if (pic[i][1] == pic[i][2] && pic[i][1] == pic[i][3] && pic[i][1] == pic[i][4]) flag ++;
    }
    if (flag == 4) return true;
    flag = 0;
    rep(i,1,4) {
        if (pic[1][i] == pic[2][i] && pic[1][i] == pic[3][i] && pic[1][i] == pic[4][i]) flag ++;
    }
    return flag == 4;
}

void rotx(int ip,int x) {
    if (x == 0) {pic[ip][5] = pic[ip][1]; rep(i,1,4) pic[ip][i] = pic[ip][i+1]; }
    else        {pic[ip][0] = pic[ip][4]; per(i,4,1) pic[ip][i] = pic[ip][i-1]; }
}

void roty(int jp,int x) {
    if (x == 0) {pic[5][jp] = pic[1][jp]; rep(i,1,4) pic[i][jp] = pic[i+1][jp]; }
    else        {pic[0][jp] = pic[4][jp]; per(i,4,1) pic[i][jp] = pic[i-1][jp]; }
}

void show() {
    rep(i,1,4) {
        rep(j,1,4) cout << pic[i][j] << ' ';
        cout << endl;
    }cout << "====================================" << endl;
}

int flag;
int get_h() {
    int r[5][5],c[5][5];
    mmm(r,0);mmm(c,0);
    rep(i,1,4) {
        rep(j,1,4) {
            r[i][pic[i][j]] ++;
            c[j][pic[i][j]] ++;
        }
    }
    int sumc = 0,sumr = 0;
    rep(i,1,4) {
        int mr = 0,mc = 0;
        rep(j,1,4) {
            mr = max(mr,r[i][j]);
            mc = max(mc,c[i][j]);
        }
        sumc += mc;
        sumr += mr;
    }
    return 4*4-max(sumc,sumr);
}

void dfs(int sum) {
    int h = get_h();  //剪枝的核心
    if (sum == 0){
        if (h == 0) flag = 1;
        return ;
    }
    if (h > sum*4) return ; //神奇

    rep(i,1,4) {
        rep(k,0,1) {
            rotx(i,k); dfs(sum-1); if (flag) return ; rotx(i,k^1);
            roty(i,k); dfs(sum-1); if (flag) return ; roty(i,k^1);
        }
    }
    return ;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T --) {
        rep(i,1,4) {
            rep(j,1,4) {
                scanf("%d",&pic[i][j]);
            }
        }
        flag = 0;
        int res = 0;
        rep(i,1,5) {
            dfs(i);
            if (flag) {
                res = i;
                break;
            }
        }
        if (res) printf("%d\n",res);
        else     printf("-1\n");
    }
}
/*
1 1 2 2
2 2 3 3
3 3 4 4
4 4 1 1
*/

猜你喜欢

转载自blog.csdn.net/qq_40513946/article/details/81394751