POJ2286:The Rotation Game

Description

POJ传送门

(简化版)只输出操作次数,不用输出方案。

Solution

直接爆搜?显然复杂度会炸。

考虑优化,我们想到 \(IDA*\)(迭代加深搜索),这篇博客默认你已经会了这个算法,如果还不会的话可以去网上搜一下。

不难发现,本题的乐观估价函数为 \(8 - cnt\)(中间 8 个数中出现次数最多的数的个数)

如果这个值加上我们已经走了的步数大于当前预期的步数,那么直接 \(return\)

反之继续搜索。

Code

我把这个 字,存到了 8 * 8 的数组中。

\(update\) (即操作)时,循环赋值。

(非常丑陋)

#include <iostream>
#include <cstdio>
#define ri register int

using namespace std;

const int N = 10;
int a[N][N];
int cnt;
int arc[8] = {5, 4, 7, 6, 1, 0, 3, 2};//回溯用的,为了反着操作一遍

inline int check(){//乐观估价函数
    int t[5] = {0};
    for(ri i = 3; i <= 5; i++)
        for(ri j = 3; j <= 5; j++)
            t[a[i][j]]++;
    ri maxs = 0;
    maxs = max(max(t[1], t[2]), t[3]);
    return 8 - maxs;
}

inline void solve_row(int row, int k){//列上操作
    if(k < 0){
        ri res = a[1][row];
        for(ri i = 1; i < 7; i++)
            a[i][row] = a[i + 1][row];
        a[7][row] = res;
    }else{
        ri res = a[7][row];
        for(ri i = 7; i > 1; i--)
            a[i][row] = a[i - 1][row];
        a[1][row] = res;
    }
}

inline void solve_line(int line, int k){//行上操作
    if(k < 0){
        ri res = a[line][1];
        for(ri i = 1; i < 7; i++)
            a[line][i] = a[line][i + 1];
        a[line][7] = res;
    }else{
        ri res = a[line][7];
        for(ri i = 7; i > 1; i--)
            a[line][i] = a[line][i - 1];
        a[line][1] = res;
    }
}

inline void update(int k){//8 个位置
    if(k == 0) solve_row(3, -1);
    else if(k == 1) solve_row(5, -1);
    else if(k == 2) solve_line(3, 1);
    else if(k == 3) solve_line(5, 1);
    else if(k == 4) solve_row(5, 1);
    else if(k == 5) solve_row(3, 1);
    else if(k == 6) solve_line(5, -1);
    else if(k == 7) solve_line(3, -1);
}

inline int dfs(int step){
    if(step == cnt){
        if(!check()) return 1;
        return 0;
    }
    if(check() + step > cnt) return 0;
    for(ri i = 0; i < 8; i++){
        update(i);
        if(dfs(step + 1)) return 1;
        update(arc[i]);//要update回来
    }
    return 0;
}

int main(){
    while(scanf("%d", &a[1][3]) && a[1][3]){
        scanf("%d%d%d", &a[1][5], &a[2][3], &a[2][5]);
        for(int i = 1; i <= 7; i++)
            scanf("%d", &a[3][i]);
        scanf("%d%d", &a[4][3], &a[4][5]);
        for(int i = 1; i <= 7; i++)
            scanf("%d", &a[5][i]);
        scanf("%d%d%d%d", &a[6][3], &a[6][5], &a[7][3], &a[7][5]);//极其丑陋的初始化
        for(cnt = 0; ; cnt++){
            if(dfs(0))
                break;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

End

posted @ 2021-09-23 21:58  xixike  阅读(26)  评论(0编辑  收藏  举报