uva 798 - Tile Puzzle(回溯)

该博客探讨了UVA 798题目,涉及使用回溯法解决拼图问题。内容包括题目描述、解题策略,指出在拼接宽度不等于高度的拼图时,可以考虑旋转操作来增加解决方案的多样性。

题目链接:uva 798 - Tile Puzzle


题目大意:给出w,h和n,表示有n种拼图,给出n种拼图的个数mi,宽wi,高hi,问说用这些拼图可以用多少中不同的方法拼凑出w*h。


解题思路:回溯法,注意拼图的宽如果不等于长的话,是可以旋转的。


#include <stdio.h>
#include <string.h>

const int N = 20;
const int M = 105;
int n, c, r, ans;
int w[N], h[N], m[N], g[M][M];

void init() {
	ans = 0;
	memset(g, 0, sizeof(g));
	for (int i = 0; i < n; i++) scanf("%d%d%d", &m[i], &w[i], &h[i]);
}

bool judge(int x, int y, int p, int q) {
	if (x + p > r || y + q > c) return false;

	for (int i = 0; i < p; i++) {
		for (int j = 0; j < q; j++) {
			if (g[x + i][y + j]) return false;
		}
	}
	return true;
}

void set(int x, int y, int p, int q, int d) {
	for (int i = 0; i < p; i++) {
		for (int j = 0; j < q; j++)
			g[x + i][y + j] = d;
	}
}

void dfs(int x, int y) {
	if (y >= c) {
		x += 1; 
		y = 0;
	}

	if (x >= r) {
		ans++; return;
	}

	if (!g[x][y]) {
		for (int i = 0; i < n; i++) if (m[i]) {

			if (judge(x, y, h[i], w[i])) {
				set(x, y, h[i], w[i], 1); m[i]--;
				dfs(x, y + 1);
				set(x, y, h[i], w[i], 0); m[i]++;
			} 

			if (judge(x, y, w[i], h[i]) && h[i] != w[i]) {
				set(x, y, w[i], h[i], 1); m[i]--;
				dfs(x, y + 1);
				set(x, y, w[i], h[i], 0); m[i]++;
			}
		}
	} else
		dfs(x, y + 1);
}

int main () {
	while (scanf("%d%d%d", &c, &r, &n) == 3) {
		init();
		dfs(0, 0);
		printf("%d\n", ans);
	}
	return 0;
}


### 使用回溯算法求解8-Puzzle问题 #### 方法概述 八数码谜题(8-puzzle),也称为九宫格拼图,是一个典型的组合搜索问题。该问题的目标是从初始状态到达目标状态,其中只有一个空白位置允许相邻的瓷砖移动。为了利用回溯法解决此问题,需要定义一个递归函数来探索所有可能的状态转换路径直到找到解决方案。 在每次迭代过程中,程序会尝试将当前空位与其四个方向上的任意一块合法邻近砖块交换位置,并记录下新的棋盘布局作为下一步操作的基础。如果某一步骤达到了预期的结果,则返回成功;否则继续深入未访问过的节点进行试探直至穷尽一切可能性或发现解答为止[^1]。 #### 实现细节 以下是Python实现的一个简单版本: ```python from copy import deepcopy def is_goal(state, goal_state): """判断是否达到目标""" return state == goal_state def find_blank_position(puzzle): """查找空白的位置""" for i in range(len(puzzle)): try: j = puzzle[i].index(0) return (i,j) except ValueError: continue raise Exception('No blank position found') moves = [(0,-1), (-1,0), (0,+1), (+1,0)] # 左 上 右 下 移动向量 def move_tile(puzzle, direction): """按照指定的方向移动空白处旁边的瓦片""" new_puzzle = deepcopy(puzzle) row,col=find_blank_position(new_puzzle) drow,dcol=direction target_row,target_col=row+drow,col+dcol if not ((0<=target_row<len(new_puzzle)) and (0<=target_col<len(new_puzzle))): return None temp=new_puzzle[target_row][target_col] new_puzzle[row][col]=temp new_puzzle[target_row][target_col]=0 return new_puzzle def backtrack_search(initial_state, goal_state): def _backtrack(current_path): current_board=current_path[-1] if is_goal(current_board,goal_state): print("Solution Found!") for step in current_path: display(step) return True possible_moves=[move for move in moves \ if move_tile(current_board,move)] visited_states=set([str(x)for x in current_path]) unvisited_neighbors=[state for state in possible_moves\ if str(state)not in visited_states] for neighbor in unvisited_neighbors: next_path=current_path+[neighbor] result=_backtrack(next_path) if result==True:return True return False start=[[initial_state]] solution_found=_backtrack(start) if not solution_found: print("No Solution Exists.") ``` 这段代码展示了如何使用回溯方法寻找从给定起始配置到结束配置的有效序列。注意这里简化了一些实际应用中的考虑因素,比如剪枝策略和启发式评估等,这些都可以进一步提高效率[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值