洛谷P1242 新汉诺塔(dfs,模拟退火)

摘要:
洛谷P1242新汉诺塔最开始的思路是贪心地将盘子从大到小依次从初始位置移动到目标位置。方法和基本的汉诺塔问题的方法一样,对于盘子,将盘子放置到中间柱子上,即号柱子。但是贪心的优先将大盘移动到指定位置存在一些特殊情况处理错误。例如如下数据,最优的方案并不是把大盘一步移到位,而是先移到了一根空柱上。3130221221013move3fromAtoBmove1fromCtoBmove2fromCtoAmove1fromBtoAmove3fromBtoC5这里使用模拟退火对算法(玄学)进行改进。因为模拟退火为随机算法,所以我们跑几百次取最优为最终答案。

洛谷P1242 新汉诺塔

最开始的思路是贪心地将盘子从大到小依次从初始位置移动到目标位置。

方法和基本的汉诺塔问题的方法一样,对于盘子 (i) ,将盘子 (1 o i-1) 放置到中间柱子上,即 (6 - from - to) 号柱子。基本递归实现。

但是贪心的优先将大盘移动到指定位置存在一些特殊情况处理错误。

例如如下数据,最优的方案并不是把大盘一步移到位,而是先移到了一根空柱上。

3
1 3
0
2 2 1
2 2 1
0
1 3

move 3 from A to B
move 1 from C to B
move 2 from C to A
move 1 from B to A
move 3 from B to C
5

这里使用模拟退火对算法(玄学)进行改进。

在移动一些盘子的时候不直接移到目标柱子上,这个不直接移到目标柱子上的操作是有一定概率的,这个概率随时间的增加而缩小。

因为模拟退火为随机算法,所以我们跑几百次取最优为最终答案。

#include<stdio.h>
#include<iostream>
#include<string>
#include<cstdlib>
#include<ctime>

using namespace std;

const int maxn = 50;
const int _time = 205;
const int inf = 0x3f3f3f3f;
int from[maxn], to[maxn], _from[maxn], _to[maxn];
int n, m, x, cnt, _cnt;
string ans, _ans, M[5] = {"0", "A", "B", "C"};

void dfs(int x, int a, int b)
{
    if(a == b) return;
    for(int i = x - 1; i >= 1; i--) dfs(i, from[i], 6 - a - b);
    from[x] = b;
    cnt++;
    ans += "move ";
    if(x>=10) ans += char(x / 10 + 48), ans += char(x % 10 + 48);
    else ans += char(x + 48);
    ans += " from "; ans += M[a]; ans += " to "; ans += M[b]; ans += "|";
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= 3; i++){
        scanf("%d", &m);
        for(int j = 1; j <= m; j++){
            scanf("%d", &x); _from[x] = i;
        }
    }
    for(int i = 1; i <= 3; i++){
        scanf("%d", &m);
        for(int j = 1; j <= m; j++){
            scanf("%d", &x); _to[x] = i;
        }
    }
    srand(time(0));
    _cnt = inf;
    for(int cas = 1; cas <= _time; cas++){
        ans = ""; cnt = 0;
        for(int i = 1; i <= n; i++) from[i] = _from[i], to[i] = _to[i];
        for(int i = n; i >= 1; i--){
            /***m模拟退火***/
            if(rand() % (n - i + 2) == 0) dfs(i, from[i], 6 - from[i] - to[i]);
            else dfs(i, from[i], to[i]);
        }
        for(int i = n; i >= 1; i--){
            dfs(i, from[i], to[i]);
        }
        if(cnt < _cnt){
            _cnt = cnt; _ans = ans;
        }
    }
    for(int i = 0; i < _ans.size(); i++){
        if(_ans[i] == '|') puts("");
        else printf("%c", _ans[i]);
    }
    printf("%d
", _cnt);
    return 0;
}

免责声明:文章转载自《洛谷P1242 新汉诺塔(dfs,模拟退火)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇解决springboot2.x项目添加@EnableDiscoveryClient注解找不到的问题python脚本之日期格式显示下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ex06 汉诺塔2 非递归解法

解法示意 需借助二进制 不妨以四层塔为例走一个 我把左、中、右三根柱子依次称为 A, B, C 金片默认都在 A 塔 n 片金片从小到大依次编号为 0, 1, 2, ... n-1 设初始值为 0000(2) 按 8, 4, 2, 1 称呼二进制的各位,对应关系如下图所示 step1 开始累加,每次加一 0000(2) => 0001...

汉诺塔——递归

汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?假如有三根柱子: 1、过程分析:...

HDU 2064 汉诺塔III(递归)

题目链接 Problem Description 约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到...

matlab练习程序(模拟退火SA)

模拟退火首先从某个初始候选解开始,当温度大于0时执行循环。 在循环中,通过随机扰动产生一个新的解,然后求得新解和原解之间的能量差,如果差小于0,则采用新解作为当前解。 如果差大于0,则采用一个当前温度与能量差成比例的概率来选择是否接受新解。温度越低,接受的概率越小,差值越大,同样接受概率越小。 是否接受的概率用此公式计算:p=exp(-ΔE/T)。这里ΔE...

递归可视化之汉诺塔的动画实现(turtle海龟)

import turtle class Stack: def __init__(self): self.items = [] def isEmpty(self): return len(self.items) == 0 def push(self, item): self.items...