uva519 - Puzzle (II)(回溯)

2024-08-24 04:38
文章标签 uva519 puzzle ii 回溯

本文主要是介绍uva519 - Puzzle (II)(回溯),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目:uva519 - Puzzle (II)


题目大意:给出拼图,要求将给出的拼图拼成 n行m列的矩形,可以输出yes,不行输出no。

解题思路:直接dfs,但是需要剪枝。

1、判断 F 的出现个数是否等于 2 * ( n + m) , 还有IO的个数是否匹配,不匹配就直接剔除,。

2、边界问题要处理,例如第一行第N行,第一列第M列,这些地方的拼图是有要求的,这些边界拼图的的外围都要是F。例如第一行的top要是F,不是F的直接不考虑。(这点导致我TL了N次)

3、相同形状的拼图,在相同一层的dfs里可以不用在考虑了。因为前面出现了一样的但是结果是不行的,所以和他相同的就不需要考虑了,但是这个仅限于同一层dfs里面,因为如果不是同一层,那么可能前面与他相邻的拼图变化了,这样这个形状的拼图可能在这种情况下就是可以的。相同形状的可以用三进制数表示,也可以排序后,直接字符串比较。

4、可以将这些拼图事先分好组,上面为F一组,下面为F的为1组,我这里分了12组。这样查找的时候就可以把范围缩小了。

前三点做到了就可以过了。


代码:(做到四点)

#include <stdio.h>
#include <string.h>const int N = 50;
const int M = 10;struct PUZZLE {int top;int left;int bottom;int right;
} puzzle[N];int rec[M][M], vis[N], list[M + 2][N];
char str[M];
int n, m, cnt[M + 2], p_value[N];
bool flag;int hash (int k) {int num;num = puzzle[k].top + puzzle[k].left * 3 + puzzle[k].bottom * 9 + puzzle[k].right * 27; return num;
}int interpret (char ch) {if (ch == 'F')return 0;if (ch == 'O')return 1;if (ch == 'I')return 2;
}void clasify (int i, int k) {if (str[i] == 'F')list[i * 3][cnt[i * 3]++] = k;else if (str[i] == 'I')list[i * 3 + 1][cnt[i * 3 + 1]++] = k;elselist[i * 3 + 2][cnt[i * 3 + 2]++] = k;
}void handle (int k) {for (int i = 0; i < strlen (str); i++) {if (i == 0) puzzle[k].top = interpret(str[i]);else if (i == 1) puzzle[k].right = interpret(str[i]);	else if (i == 2) puzzle[k].bottom = interpret(str[i]);	elsepuzzle[k].left = interpret(str[i]);clasify (i, k); }
}void dfs (int x, int y) {if (flag)return;if (x > n) {flag = 1;return ;}int k, map[M * M];memset (map , 0, sizeof (map));if (x == 1)k = 0;else if (x == n)k = 6;else if (y == 1)k = 9;else if (y == m)k = 3;else  {if (puzzle[rec[x - 1][y]].bottom == 0) k = 0;	else if (puzzle[rec[x - 1][y]].bottom == 1)k = 1;else if (puzzle[rec[x - 1][y]].bottom == 2)k = 2;else if (puzzle[rec[x][y - 1]].right == 0)k = 9;else if (puzzle[rec[x][y - 1]].right == 1)k = 10;else if (puzzle[rec[x][y - 1]].right == 2)k = 11;}for (int i = 0; i < cnt[k]; i++) {if (map[p_value[list[k][i]]])continue;if (vis[list[k][i]])continue;if (!((puzzle[list[k][i]].left + puzzle[rec[x][y - 1]].right) % 3) && !((puzzle[list[k][i]].top + puzzle[rec[x - 1][y]].bottom) % 3)) {rec[x][y] = list[k][i];vis[list[k][i]] = 1;if (y + 1 > m) dfs (x + 1, 1);elsedfs (x, y + 1);if (flag)return;vis[list[k][i]] = 0;map[p_value[list[k][i]]] = 1;}}
}void init () {flag = 0;memset (cnt, 0, sizeof (cnt));memset (rec, 0, sizeof (rec));memset (vis, 0, sizeof (vis));memset (list, 0, sizeof (list));puzzle[0].top = puzzle[0].left = puzzle[0].bottom = puzzle[0].right = 0;}int main () {while (scanf ("%d%d", &n, &m) , n || m) {init ();	for (int i = 1 ; i <= n * m; i++) {scanf ("%s", str);handle(i);}int n1 = 0, n2 = 0;for (int i = 0; i < 4; i++) {n1 += cnt[i * 3 + 1];n2 += cnt[i * 3 + 2];}if (cnt[0] == m && n1 == n2 && cnt[3] == n && cnt[6] == m && cnt[9] == n) { for (int i = 1; i <= n * m; i++)  p_value[i] = hash(i);dfs (1, 1);}printf ("%s\n", flag == 1?"YES":"NO");}return 0;
}
代码:(做到三点)

#include <stdio.h>
#include <string.h>const int N = 50;
const int M = 10;struct PUZZLE {int top;int left;int bottom;int right;
} puzzle[N];int rec[M][M], vis[N];
char str[M];
int n, m, p_value[N];
bool flag;
int c1, c2, c0;int hash (int k) {int num;num = puzzle[k].top + puzzle[k].left * 3 + puzzle[k].bottom * 9 + puzzle[k].right * 27; return num;
}int interpret (char ch) {if (ch == 'F')return 0;if (ch == 'O')return 1;if (ch == 'I')return 2;
}void handle (int k) {for (int i = 0; i < strlen(str); i++) {if (i == 0) puzzle[k].top = interpret(str[i]);else if (i == 1) puzzle[k].right = interpret(str[i]);	else if (i == 2) puzzle[k].bottom = interpret(str[i]);	elsepuzzle[k].left = interpret(str[i]);if (str[i] == 'F')c0++;else if (str[i] == 'O')c2++;elsec1++;}
}void dfs (int x, int y) {if (flag)return;if (x > n) {flag = 1;return ;}int k, map[M * M];memset (map , 0, sizeof (map));for (int i = 1; i <= n * m; i++) {if (x == 1 && puzzle[i].top != 0)continue;if (x == n && puzzle[i].bottom != 0)continue;if (y == 1 && puzzle[i].left != 0)continue;if (y == m && puzzle[i].right != 0)continue;if (map[p_value[i]])continue;if (vis[i])continue;if (!((puzzle[i].left + puzzle[rec[x][y - 1]].right) % 3) && !((puzzle[i].top + puzzle[rec[x - 1][y]].bottom) % 3)) {rec[x][y] = i;vis[i] = 1;if (y + 1 > m) dfs (x + 1, 1);elsedfs (x, y + 1);if (flag)return;vis[i] = 0;map[p_value[i]] = 1;}}
}void init () {flag = 0;memset (rec, 0, sizeof (rec));memset (vis, 0, sizeof (vis));c1 = c2 = c0 = 0;puzzle[0].top = puzzle[0].left = puzzle[0].bottom = puzzle[0].right = 0;}int main () {while (scanf ("%d%d", &n, &m) , n || m) {init ();	for (int i = 1 ; i <= n * m; i++) {scanf ("%s", str);handle(i);}if (c1 == c2 &&  c0 == 2 * (m + n)) { for (int i = 1; i <= n * m; i++)  p_value[i] = hash(i);dfs (1, 1);}printf ("%s\n", flag == 1?"YES":"NO");}return 0;
}



这篇关于uva519 - Puzzle (II)(回溯)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101474

相关文章

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

回溯——9.全排列

力扣题目链接 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 解题思路 问题建模:题目要求给出一个数组的所有排列组合,属于典型的全排列问题,这可以用回溯法来解决。回溯法通过递归的方式,依次将数组中的每个元素放入排列中,直到生成

LeetCode:3177. 求出最长好子序列 II 哈希表+动态规划实现n*k时间复杂度

3177. 求出最长好子序列 II 题目链接 题目描述 给你一个整数数组 nums 和一个非负整数k 。如果一个整数序列 seq 满足在下标范围 [0, seq.length - 2] 中 最多只有 k 个下标i满足 seq[i] != seq[i + 1] ,那么我们称这个整数序列为好序列。请你返回 nums中好子序列的最长长度。 实例1: 输入:nums = [1,2,1,1,3],

代码训练营 Day26 | 47.排序II | 51. N-皇后 |

47.排序II 1.跟46题一样只不过加一个树层去重 class Solution(object):def backtracking(self,nums,path,result,used):# recursion stopif len(path) == len(nums):# collect our setresult.append(path[:])return for i in range(

代码随想录训练营day37|52. 携带研究材料,518.零钱兑换II,377. 组合总和 Ⅳ,70. 爬楼梯

52. 携带研究材料 这是一个完全背包问题,就是每个物品可以无限放。 在一维滚动数组的时候规定了遍历顺序是要从后往前的,就是因为不能多次放物体。 所以这里能多次放物体只需要把遍历顺序改改就好了 # include<iostream># include<vector>using namespace std;int main(){int n,m;cin>>n>>m;std::vector<i

风控系统之指标回溯,历史数据重跑

个人博客:无奈何杨(wnhyang) 个人语雀:wnhyang 共享语雀:在线知识共享 Github:wnhyang - Overview 回顾 默认你已经看过之前那篇风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法。 其中已经介绍了如何利用redis的zset结构完成指标计算,为了方便这篇文章的介绍,还是在正式开始本篇之前回顾一下。 时间窗口 zset

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II 1.题目 1.1递增子序列 题目链接:491. 非递减子序列 - 力扣(LeetCode) 视频讲解:回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列_哔哩哔哩_bilibili 文档讲解:https://programmercarl.com/0491.%E9%80%92%E

代码随想录算法训练营Day37|完全背包问题、518.零钱兑换II、377. 组合总和 Ⅳ、70. 爬楼梯(进阶版)

完全背包问题                  和01背包最大区别就是一个物品可以重复放多次,因此遍历空间时可以从前往后。 import java.util.*;public class Main{public static void main (String[] args) {Scanner sc = new Scanner(System.in);int m = sc.nextInt