zoukankan      html  css  js  c++  java
  • 洛谷P1242 新汉诺塔(dfs,模拟退火)

    洛谷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;
    }
    
  • 相关阅读:
    WPF 自适应布局控件
    c# 将Datarow转成Datarowview
    C# 全局Hook在xp上不回调
    WPF datagrid AutoGenerateColumns隐藏部分列
    WPF wpf中按钮操作权限控制
    C# autofac配置文件中设置单例
    Castle ActiveRecord 二级缓存使用 异常记录
    VS2013 抛出 stackoverflow exception 的追踪
    CastleActiveRecord在多线程 事务提交时数据库资源竞争导致更新失败的测试结果记录
    WF4.0 工作流设计器 传入参数问题记录?
  • 原文地址:https://www.cnblogs.com/solvit/p/11385586.html
Copyright © 2011-2022 走看看