Cubic Eight-Puzzle UVA - 1604

有一定难度的一道题目,关键在于剪枝的使用。首先将空白用0来标志,1标志红色,2标志蓝色,3标志白色,然后读入数据,开始进行深搜,每次深搜的时候记录上一次的空白的位置,同时找出当前的空白的位置,通过保证此次移动方块之后所产生的空白位置不会和之前的重复,这样来剪枝提高效率,同时在每次递归的时候要判断目前的状态和目标的状态有多少个位置的不同,如果有n个不同,同时当前操作了k次,那么n+k如果大于ans(当前的最优值,初始化为30,因为30次操作最多会改变31个位置),则直接返回。通过上述两种方式的剪枝就可以了,具体实现见如下代码:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
using namespace std;

int x, y;
int aim[3][3],ans;
pair<int,int> area[3][3];//0 空白 1 红色 2 蓝色 3 白色  上方和前方

int dx[] = {1,-1,0,0};
int dy[] = {0,0,1,-1};

int compare(){//统计有多少个不同
	int amount = 0;
	for (int i = 0; i < 3; i++){
		for (int j = 0; j < 3; j++){
			if (area[i][j].first != aim[i][j]) amount++;
		}
	}
	return amount;
}

void Move(int nx,int ny,int type){
	int curx=nx+dx[type], cury=ny+dy[type];
	if (type == 0 || type == 1){//上下移动
		swap(area[nx][ny].first,area[nx][ny].second);
	}
	else{//左右移动
		int color = 1 ^ 2 ^ 3 ^ area[nx][ny].first^area[nx][ny].second;
		area[nx][ny].first = color;
	}
	swap(area[curx][cury],area[nx][ny]);
}

void dfs(int curx,int cury,int depth){
	int amount2 = compare();
	if (amount2 == 0){
		ans = min(ans,depth);
		return;
	}
	if (amount2 + depth > ans){
		return;
	}
	int tx, ty;
	for (int i = 0; i < 3; i++){
		for (int j = 0; j < 3; j++){
			if (!area[i][j].first){
				tx = i; ty = j;
				break;
			}
		}
	}
	for (int i = 0; i < 4; i++){
		int next_x = tx + dx[i];
		int next_y = ty + dy[i];
		if (next_x >= 0 && next_x < 3 && next_y >= 0 
			&& next_y < 3 && (next_x != curx||next_y != cury)){
			Move(next_x, next_y, i ^ 1);
			dfs(tx, ty, depth + 1);
			Move(tx, ty, i);
		}
	}
}

int main(){
	while (cin >> y >> x){
		if (x == 0 && y == 0) break;
		x--; y--;
		for (int i = 0; i < 3; i++){
			for (int j = 0; j < 3; j++){
				char t;
				cin >> t;
				if (t == 'E') aim[i][j] = 0;
				else if (t == 'R') aim[i][j] = 1;
				else if (t == 'B') aim[i][j] = 2;
				else aim[i][j] = 3;
				if (i == x&&j == y) area[i][j] = make_pair(0,0);
				else area[i][j] = make_pair(3,1);
			}
		}
		ans = 31;
		dfs(-1, -1, 0);
		if (ans > 30) ans = -1;
		cout << ans << endl;
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值