UVa1601 Morning after holloween 解题分析

只有思路还没有实践

这个题一眼看上去就是典型的状态空间搜索问题,a,b,c的每一个不同摆放位置都是一个状态,每一个状态都可以看成无权有向无环状图上的一个节点。又是找移动步数最少的走法,很自然就会想到用BFS。

细想上去,这个题稍微麻烦的地方是,如何从一个状态扩展到下一个状态。每个状态有2个或者3个字母需要考虑。 本以为只要考虑先尝试移动a,然后b,最后考虑移动c, 每个字母在四个方向上各尝试移动一步就可以了,那么对于一个状态,需要尝试的下一个状态数目只是4*4*4。其实不对,第一步移动a和第一步移动c,形成的状态可能完全是不一样的,那么需要尝试的顺序不止是a,b,c这么简单,这三个字母的全排列都是可能需要尝试的顺序。那么abc的排列个数一共有6个, {a,b,c},{a,c,b},{b,a,c},...etc. 那么需要尝试的下一个状态个数是6*4*4*4个。

这样其实还不完整,因为除了移动顺序不同,可能产生的状态不同以外, 还需要考虑某一两个字母不动的情况,比如只有c移动了一步,a和b完全不动, 这也会产生一种新状态。所以可能的移动顺序并不是abc的全排列,而是除空集以外所有子集的全排列,如{a},{b},{c},{a,b},{b,a}...etc,这样一来要尝试的顺序就变得更多。abc的子集有{a},{b},{c},{a,b},{b,c},{a,c},{a,b,c},他们的全排列一共15个,也就是说最后要尝试的状态个数是15*4*4*4共960种!当然这中间大多数是不合法的,最后真正能压入BFS队列的可能很少。

那么重960种候选状态中那些是合法的?需要做如下判断

1)字母不能摆出图形的边界

2)字母不能摆在障碍上

3)字母不能摆在另一个字母上

4)形成的状态不能是以前处理过的状态

这四项判断应该能筛除掉掉大部分的备选状态。

要进行这四项判断,必须有一个数据结构来保存原始的底图,用二维数组来标明,哪个位置有障碍,哪个位置可以摆放。这个图的长宽要保留下来做是否出界的判断。还要有一个数据结构用来保留已经处理过的状态,确保不重复处理同一个状态,这个数据结构应该是个hash的结构,现在还没想好怎么做。

题目要求打印需要最少的步数,那么每一个状态中应该有一个数据用来保存这个状态是在第几步产生的。查询的结束条件有两个:一个是找到的状态和目标状态完全一致,那么查找成功;一个是所有的状态全部处理完毕,BFS队列全空,说明没有一条路径可以到达目标状态。

原题中要移动的字母也可能只有a,b两个,它的子集和排列都少很多,要尝试的下一个状态也少很多,但是这个变化稍稍增加了题目的复杂度。还好这题只是要打印步数,如果要打印路径,那就更麻烦,在每一个已处理过的状态中要有一个指针指向上一个状态。最后在倒着把这个列表打出来。一个状态可以扩展出很多子状态,但是每个子状态只有一个父状态。

这个题的思路就是这样的,标准的状态空间搜索,就是条件太多,写起来是个力气活儿,调起来更是不敢想, 现在有点懒得写,不知道还有没有更好的方法,要不要真的这么麻烦?

时间: 2024-10-11 14:26:02

UVa1601 Morning after holloween 解题分析的相关文章

[rctf](web)rcdn 解题分析,知识点总结

比赛平台关闭了,没有截图,见谅. 解题思路流程: 分析网站结构,看源码,元素审计.发现以下信息. 要得到flag要获得一个pro cdn pro 子域名长度为3到6个字符 存在一个提交ticke页面 那怎么获取一个pro cdn呢?想到以下几种方法. 直接申请一个pro cdn 能不能把一个basic提升为pro 登录admin的账号,看里面是否有pro cdn 无从申请. 设计pro的操作时都提示不允许. 尝试注入,弱密码无效. 这些弄完了之后,思路卡壳,回到提交ticket那里. 十分肯定最

搜狗2015C++工程师笔试题解题分析

试卷链接:搜狗2015 C++工程师笔试题. 1.假设整数0x12345678 存放在内存地址0x0开始的连续四个字节中 (即地址0x0到 0x3). 那么在以Little Endian字节序存储的memory中,地址0x3的地方存放的字节是: 0x12 0x34 0x56 0x78 分析:选D.小端法和大端法. a) Little-Endian就是低位字节排放在内存的低地址端, 高位字节排放在内存的高地址端. b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地

2015年蓝桥杯省赛B组C/C++(试题+答案)

首先说,这次我是第二次参加蓝桥杯(大学里最后一次),可这次去连个三等都没拿到,有些心灰意冷,比上一次还差, 当时看到成绩出来的时候有些失落,但是跌倒了,再站起来继续跑就可以了.可能是状态不好吧,纯属自我安慰. 接下来我把今年的题目又重新做了一遍,写下了这篇博客,如果也有需要探讨答案的,希望可以有帮助. 第一题: 第1题:统计不含4的数字 题目大意 统计10000至99999中,不包含4的数值个数. 解题分析: 第一种解法: 数学方法,这种是在网上看到的一种解法: 最高位除了0.4不能使用,其余8

m个苹果放入n个盘子问题

问题一 问题描述:把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问有多少种不同的分法?(注:5,1,1和1,1,5是同一种分法) 解题分析: 设f(m,n)为m个苹果,n个盘子的放法数目,则先对n作讨论, 当n>m:则必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响.即 if(n>m) f(m,n) = f(m,m) 当n <= m:不同的放法可以分成两类:含有0的方案数,不含有0的方案数 1.含有0的方案数,即有至少一个盘子空着,即相当于 f(m,n)=f

Leetcode:Partition List 链表快速排序划分

Partition List Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the nodes in each of the two partitions. For example,Given

code vs 2597 团伙

题目描述 Description 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友. 两个强盗是同一团伙的条件是当且仅当他们是朋友.现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙. 输入描述 Input Description 输入文件gangs.in的第一行是一个整数N(2<=N<=1000),表示强盗的个数(从1编号到N). 第二行M(1<=M<=500

codeforces gym 100357 H (DP 高精度)

题目大意 有r*s张扑克牌,数字从1到 r,每种数字有s种颜色. 询问对于所有随机的d张牌,能选出c张组成顺子的概率和组成同花的概率. 解题分析 对于组成顺子的概率,令dp[i][j][k]表示一共选出了i张牌,数字从1~j,最后有k张牌是顺子.对于每个数字进行考虑,有0~s种选法.要保证连续c张牌的顺子. 对于组成同花的概率,令dp[i][j]表示一共选出了i张牌,颜色从1~j,.对于每种颜色进行考虑,有0~r种选法.要保证没有c张牌是相同颜色的. 最后用高精度来输出答案. 参考程序 1 #i

Hihocoder 1329(splay)

Problem 平衡树 Splay 题目大意 维护一个数列,支持三种操作. 操作1:添加一个数x. 操作2:询问不超过x的最大的数. 操作三:删除大小在区间[a,b]内的数. 解题分析 和上一题相比,多了一个删除的操作. 首先将a的前驱节点x旋转到根,然后将b的后驱节点y旋转到x的右孩子,这样所有大小在[a,b]内的数均位于y的左子树内,直接将其删掉就可以了. 为了防止找不到x和y,在初始化时向树中插入一个极大值和一个极小值. 参考程序 1 #include <bits/stdc++.h> 2

BZOJ3669 (动态树)

Problem 魔法森林 (NOI2014) 题目大意 给n个点,m条边的无向图,每条边有两个权值a,b. 求一条从1-->n的路径,使得这条路径上max(a)+max(b)最小.输出最小值即可. 解题分析 将边按照权值a从小到大排序后,依次加边,用lct维护一棵最小生成树. 具体做法是如果所加边u-->v导致形成了一个环,那么比较一下u-->v路径中的最大值和这条边的b权值大小,来决定取那条边. 处理边权的一个做法,将每条边看成一个新的点,向其两端的点连边. 参考程序 1 #inclu