AcWing 181:回转游戏 ← IDA*

【题目来源】
https://www.luogu.com.cn/problem/UVA1343
https://www.acwing.com/problem/content/description/183/

【题目描述】
如下图所示,有一个 # 形的棋盘,上面有 1,2,3 三种数字各 8 个。
给定 8 种操作,分别为图中的 A∼H。
这些操作会按照图中字母和箭头所指明的方向,把一条长为 7 的序列循环移动 1 个单位。
例如下图最左边的 # 形棋盘执行操作 A 后,会变为下图中间的 # 形棋盘,再执行操作 C 后会变成下图最右边的 # 形棋盘。
给定一个初始状态,请使用最少的操作次数,使 # 形棋盘最中间的 8 个格子里的数字相同。

【输入格式】
输入包含多组测试用例。
每个测试用例占一行,包含 24 个数字,表示将初始棋盘中的每一个位置的数字,按整体从上到下,同行从左到右的顺序依次列出。
输入样例中的第一个测试用例,对应上图最左边棋盘的初始状态。
当输入只包含一个 0 的行时,表示输入终止。

【输出格式】
每个测试用例输出占两行。
第一行包含所有移动步骤,每步移动用大写字母 A∼H 中的一个表示,字母之间没有空格,如果不需要移动则输出 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

【算法分析】
● 打表:棋盘是 # 形,为了方标取数和操作,可给这些位置按下图所示依次编号为0~23,同时给A~G这8个操作依次编号为0~7。

● 估价函数:因为每次操作只会改变中心8个方格里的一个数,而题目要求中心8个方格的数都相同,故最小代价= 8-max(sum[i],i=1,2,3)
● 剪枝:排除等效冗余。假如先A后F,那么结果其实没有变化,视为无效操作。所以,要避免相邻两次的操作是对立的。

【算法代码】

/*
      0     1
      2     3
4  5  6  7  8  9  10
      11    12
13 14 15 16 17 18 19
      20    21
      22    23
*/

#include <bits/stdc++.h>
using namespace std;

const int maxn=24;
int in[maxn]; //Store 24 cells using 1,2,or 3.

//Eight operations. Each operation has 7 cells.
//The contents of op[8][7] are cells' IDX.
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 center[]= {6,7,8,11,12,15,16,17}; //cells' IDX of the center 8 cells
int inver[]= {5,4,7,6,1,0,3,2}; //inverse operations' IDX

int ans[100]; //The elements of the output sequence

int h() { //evaluation function
	int sum[4]; //sum[i] save the number of the cells which content is i.
	memset(sum,0,sizeof(sum));
	//The number of cells which contents are 1, 2, or 3
	for(int i=0; i<8; i++) sum[in[center[i]]]++;

	int s=0; //The max number of central 8 cells with values of 1,2 or 3
	for(int i=1; i<=3; i++) s=max(s,sum[i]);
	return 8-s;
}

bool check() { //Check the values of the central 8 cells whether are equal
	for(int i=1; i<8; i++)
		if(in[center[i]]!=in[center[0]]) return false;
	return true;
}

void move(int x) { //move cells
	int t=in[op[x][0]]; //The IDX of the first cell of each moveation
	for(int i=0; i<6; i++) in[op[x][i]]=in[op[x][i+1]]; //move cells
	in[op[x][6]]=t;
}

bool dfs(int cur,int dep,int pre) {
	if(cur+h()>dep) return false;
	if(check()) return true;

	for(int i=0; i<8; i++) {
		if(inver[i]==pre) continue;
		move(i);
		ans[cur]=i; //Reasons for next printf("%c",'A'+ans[i]);
		if(dfs(cur+1,dep,i)) return true;
		move(inver[i]);
	}

	return false;
}

int main() {
	while(scanf("%d", &in[0])) {
		if(in[0]==0) break;
		for(int i=1; i<maxn; i++) scanf("%d", &in[i]);

		int maxd=0;
		while(!dfs(0,maxd,-1)) {
			maxd++;
		}
		if(!maxd) printf("No moves needed");
		for(int i=0; i<maxd; i++) printf("%c",'A'+ans[i]);

		printf("\n%d\n", in[6]);
	}

	return 0;
}


/*
in:
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

out:
AC
2
DDHH
2
*/


【参考文献】
https://blog.csdn.net/qq_45432665/article/details/104136841
https://www.acwing.com/solution/content/4056/
https://www.cnblogs.com/hhlya/p/13380633.html
https://blog.csdn.net/qq_51392086/article/details/119814637
https://blog.csdn.net/qiaodxs/article/details/125358842
https://www.cnblogs.com/NoahBBQ/p/15149295.html
https://www.cnblogs.com/newblg/p/14679401.html




 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值