AcWing181.回转游戏(IDA*)

 题目:https://www.acwing.com/problem/content/183/

如下图所示,有一个“#”形的棋盘,上面有1,2,3三种数字各8个。

给定8种操作,分别为图中的A~H。

这些操作会按照图中字母和箭头所指明的方向,把一条长为8的序列循环移动1个单位。

例如下图最左边的“#”形棋盘执行操作A后,会变为下图中间的“#”形棋盘,再执行操作C后会变成下图最右边的“#”形棋盘。

给定一个初始状态,请使用最少的操作次数,使“#”形棋盘最中间的8个格子里的数字相同。

2286_1.jpg

输入格式

输入包含多组测试用例。

每个测试用例占一行,包含24个数字,表示将初始棋盘中的每一个位置的数字,按整体从上到下,同行从左到右的顺序依次列出。

输入样例中的第一个测试用例,对应上图最左边棋盘的初始状态。

当输入只包含一个“0”的行时,表示输入终止。

输出格式

每个测试用例输出占两行。

第一行包含所有移动步骤,每步移动用大写字母“A~G”中的一个表示,字母之间没有空格,如果不需要移动则输出“No moves needed”。

第二行包含一个整数,表示移动完成后,中间8个格子里的数字。

如果有多种方案,则输出字典序最小的解决方案。

输入样例:

1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0

输出样例:

AC
2
DDHH
2

题解: 这道题我们考虑搜索,但是由于状态较多,需要一些优化:1.每次枚举操作时,我们不考虑与上次操作产生抵消效果的操作。2.每次我们考虑一个函数,如果cnt+f()> step,也就是无法在step前完成,直接回溯。另外,由于操作本身比较复杂,我们将操作和操作的数的下标进行编号,这样可以简化代码。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,b,a) for(int i=b;i>=a;i--)
#define Mst(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&-x
const int N = 105;
int op[8][7] = {
    {0,2,6,11,15,20,22},
    {1,3,8,12,17,21,23},
    {10,9,8,7,6,5,4},
    {19,18,17,16,15,14,13},
    {23,21,17,12,8,3,1},
    {22,20,15,11,6,2,0},
    {13,14,15,16,17,18,19},
    {4,5,6,7,8,9,10}
};
int opposite[] = {5,4,7,6,1,0,3,2};
int center[] = {6,7,8,11,12,15,16,17};
int path[N],a[N];
int f() {
    int sum[4] = {0};
    int maxn = 0;
    rep(i,0,7) {
       sum[a[center[i]]]++;
    }
    rep(i,1,3) maxn = max(maxn,sum[i]);
    return 8-maxn;
}
void make(int x) {
    int t = a[op[x][0]];
    rep(i,0,5) a[op[x][i]] = a[op[x][i+1]];
    a[op[x][6]] = t;
}
bool dfs(int cnt,int step,int last) {
    if(cnt + f() > step) return false;
    
    if(f() == 0) return true;
    
    rep(i,0,7) {
        if(opposite[i] == last) continue;
        path[cnt] = i;
        make(i);
        if(dfs(cnt+1,step,i)) return true;
        make(opposite[i]);
    }
    
    return false;
}
int main() {
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin >> a[0] && a[0]) {
        rep(i,1,23) cin >> a[i];
        int step = 0;
        while(!dfs(0,step,-1)) step++;
        
        if(!step) {
             cout << "No moves needed" << endl;
             cout << a[center[0]] << endl;
        }
        else {
            rep(i,0,step-1) cout << (char)(path[i] + 'A');
            cout << endl;
            cout << a[center[0]] << endl;
        }
        
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值