关于 double sort 这道题的思考

声明

   笔者最近意外的发现 笔者的我的网站 http://tiankonguse.com/ 的不少文章被其它网站转载,可是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,所以,笔者添加此条声明。php

    郑重声明:这篇记录《关于 double sort 这道题的思考》转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=651git

 

前言

前言的前言github

昨天原本写好了这篇记录,可恨中间我出去打了一个电话,回来继续写,写完我想到可能session已经失效,因此我新打开一个页面,登陆,而后在这个页面提交。返回了提交成功的标签,可是跳转到那篇文章时提示不存在。这个,我不能再忍受了,因而本身作了一个自动保存的功能。算法

 

首先今天写的内容将会简短,由于昨天写的很久很久,结果自动保存功能尚未实现。不过如今,时刻都在自动保存着,不再用担忧这个问题了。session

首先声明这篇记录不是解题报告,只是一场个人大脑里思路的旅行。函数

 

前几天学弟学妹们有一场比赛,学弟邀请我做为技术支持者去帮忙,在那个过程当中我看了几道题。网站

其中有两道题正常比赛没有其余人提交,因而我研究了一下。队列

研究的第一道就一个暴力dfs就能够过,只是可能正常比赛没人看懂题意,我看了好几个小时才看懂的。内存

第二道就是 double sort。开发

 

正文

题意

 

什么是 double sort 呢?

就以题目中的讲解例子来讲说吧。

题目说对于一组数 [5; 4; 3; 2; 1], 若是只能够交换相邻的数字,要使这组数达到升序至少须要 10 步。

这个很好理解,假设一个数字要和左面的数字交换,那只有一种状况。

可是对于两组数 [5,5; 4,4; 3,3; 2,2; 1,1] 来讲,也是只能交换相邻的数字。这是一个数字和左面的数字交换时就有两种状况了。

好比对于 4 能够和 第一个5交换,也能够和第二个5交换。

目标是使这两组数字达到升序。题意还说这个例子的答案是 15 ,不是 20.

 

而后,没而后了。

 

错误的题意

看完上面的题意,我有一个疑问:难道真的是要排成 [5,5; 4,4; 3,3; 2,2; 1,1] 的样子吗? 15 步可能吗?

因而我猜想多是达到每组升序便可,好比 [4,5; 4,5; 2,3; 2,3; 1,1], 这样第一组是 [4; 4; 2; 2; 1], 第二组书[5; 5; 3; 3; 1].

因而我写了一个暴力程序,第一组样例还真跑出一个 15 的答案来。

可是第二组 答案大小比样例少了1。

 

既然结果不正确,那就须要把那个正确的答案的路径输出来,看看有什么不一样。

结果发现最终答案应该是上下两个的差不超过2.

因而我添加了一个 fix 函数,修正这种状况。

而后三个样例都过了。

再而后就是 WA 了。

 

正确的题意

而后我想仍是想弄明白题意再说,因而用 [3,3; 2,2; 1,1] 模拟了一下,发现真的比 [3; 2; 1] 的答案的二倍少。

这时我意识到可能目标真的是求[1,1; 2,2; 3,3]  这种状况。

 

暴力DFS尝试

知道了题意,数据量只是到8,因而写了一个暴力程序。

使用 "1122334455" 串的形式map 了一下。

对于5瞬间跑出答案,对于6 跑了好一会。

 

双向DFS搜索

直接搜太慢,那就双向搜试试。

因而写了一个双向 DFS, 结果 6也是瞬间跑出来,可是 7 怎么也出不来了。

 

使用逆序数剪枝双向搜索

写的虽然是双向DFS,可是其实仍是暴力搜索,尚未加什么剪枝。

因而使用 逆序数剪枝, 7 十秒多跑出来了。

因而提交试试,发现 超内存,如今不是时间问题了,是内存不够的问题了。

 

状态压缩

内存不够就要想法节省内存,其中 map<string, string>最浪费内存。

为何要使用 string 呢?

为了保存一个状态。

那能不能使用位数压缩状态么?

发现还真的能够。

数字是从1-8,也就是0-7 了。最少须要三位才能表示一个数字,总共须要 24位数字,3字节,long long 类型的能够。

因而修改为map<LL, LL>.

为何要使用 map 呢?

貌似是为了记录路径,这里不须要记录路径。

因而修改为为了 set<LL> .

再次提交仍是超内存。

 

A* 算法出世

究竟是为何会超内存呢?

由于状态太多了。

为何状态太多了呢?

由于咱们使用的暴力搜索,咱们不知道哪一个状态是最优解,哪一个不是。

那能不能确认某个状态必定比另外一个状态更优呢?

貌似能够的。

那就用优先队列吧。

因而问问学弟小堆是使用大于号仍是小于号。最后本身在模板生找到了。

 

A*搜索的估价函数

双向搜索时曾遇到过逆序数,因而使用逆序数做为估价函数吧。

7 终于跑出来了。

可是 8 仍是跑步出来。

 

A*搜索的另外一个估价函数

逆序数这个估价函数行吗?

貌似偏差太大,无效状态太多。

那能不能换一个估价函数呢?

貌似还真有一个,每一个数字离本身最终的位置的距离也是一个不错的估价汗是。

那就使用这个估价函数吧。

因而把估价函数换了换,结果仍是只能跑出7来。

 

强强联合

怎么仍是跑不出 8 呢?

估价函数太弱,精度过低。

那能不能增强估价函数呢?

貌似能够的。

好比说呢?

对于逆序数,交换一次最多减小3个逆序数,最少一个。

对于相对距离,交换一次最多减小两个,最少不变。

知道了,就这个办呢。

因而使用两个估计函数,从新了程序,结果7确实跑的快乐,可是仍是跑不出8来。

 

总结

这道题虽然没有跑出 8 来,可是收获很多。

首先这一切都是本身独立思考的,再次开发了智力。

有兴趣的人能够继续思考下去,尽可能不要看解题报告。

全部代码都在这里 https://github.com/tiankonguse/ACM/tree/master/hust/doublesort

参考

tiankonguse 的模板

相关文章
相关标签/搜索