P1242 新汉诺塔(搜索+模拟退火)

Posted lubixiaosi-zhaocao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1242 新汉诺塔(搜索+模拟退火)相关的知识,希望对你有一定的参考价值。

题目链接:传送门

题目大意:

汉诺塔,给定n个盘子(n <= 45),起始状态和结束状态,求最小的步数以及路径。

思路:

考虑用dfs贪心地将剩余最大盘归位。

技术分享图片
#include<bits/stdc++.h>

using namespace std;
const int MAX_N = 50;
const int SUM = 3;

int N, ans;
int f1[MAX_N], f2[MAX_N];

void dfs(int cur, int st, int ed, bool now)
{
    int mid = SUM - st - ed;
    if (st == ed) {
        if (cur > 1)
            dfs(cur-1, f1[cur-1], now ? f2[cur-1] : ed, now);
        return;
    }
    if (cur > 1)
        dfs(cur-1, f1[cur-1], mid, false);
    ans++;
    printf("move %d from %c to %c
", cur, A + st, A + ed);
    f1[cur] = ed;
    if (cur > 1)
        dfs(cur-1, f1[cur-1], now ? f2[cur-1] : ed, now);
}

void input()
{
    ans = 0;
    cin >> N;
    for (int i = 0; i < 6; i++) {
        int x;
        cin >> x;
        while (x--) {
            int cur;
            cin >> cur;
            if (i/3)
                f2[cur] = i%3;
            else
                f1[cur] = i%3;
        }
    }
}

int main(){
    input();
    dfs(N, f1[N], f2[N], true);
    cout << ans << endl;
    return 0;
}
View Code

 

以上代码会被这组数据hack。

技术分享图片
/*
3
1 3
0
2 2 1
2 2 1
0
1 3
*/
View Code

 

但是大多数情况下贪心思路没有问题,所以用模拟退火优化。

技术分享图片
#include<bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX_N = 50;
const int SUM = 3;

int N, ans, icur;
string sans, scur;
int ff1[MAX_N], ff2[MAX_N];
int f1[MAX_N], f2[MAX_N];

void mov(int cur, int st, int ed)
{
    icur++;
    scur += "move ";
    if (cur >= 10)
        scur += char(cur/10 + 0);
    scur += char(cur%10 + 0);
    scur += " from ";
    scur += char(st + A);
    scur += " to ";
    scur += char(ed + A);
    scur += "
";
}

void dfs(int cur, int st, int ed, bool now)
{
    int mid = SUM - st - ed;
    if (st == ed) {
        if (cur > 1)
            dfs(cur-1, f1[cur-1], now ? f2[cur-1] : ed, now);
        return;
    }
    if (cur > 1)
        dfs(cur-1, f1[cur-1], mid, false);
    mov(cur, st, ed);
    f1[cur] = ed;
    if (cur > 1)
        dfs(cur-1, f1[cur-1], now ? f2[cur-1] : ed, now);
}

void input()
{
    ans = INF;
    cin >> N;
    for (int i = 0; i < 6; i++) {
        int x;
        cin >> x;
        while (x--) {
            int cur;
            cin >> cur;
            if (i/3)
                ff2[cur] = i%3;
            else
                ff1[cur] = i%3;
        }
    }
}

int main(){
    input();
    int T = 100;
    srand(44356542);
    while (T--) {
        icur = 0;
        scur = "";
        for (int i = 1; i <= N; i++) {
            f1[i] = ff1[i];
            f2[i] = ff2[i];
        }
        for (int i = N; i >= 1; i--) {
            if (rand()%(i+1) != 0)
                dfs(i, f1[i], f2[i], true);
            else
                dfs(i, f1[i], SUM-f1[i]-f2[i], true);
        }
        dfs(N, f1[N], f2[N], true);
        if (ans > icur) {
            ans = icur;
            sans = scur;
        }
    }
    cout << sans << ans << endl;
    return 0;
}
/*
3
1 3
0
2 2 1
2 2 1
0
1 3
*/
View Code

 

以上是关于P1242 新汉诺塔(搜索+模拟退火)的主要内容,如果未能解决你的问题,请参考以下文章

P1242 新汉诺塔

uoj167 元旦老人与汉诺塔(记忆化搜索)

汉诺塔VII(递推,模拟)

汉诺塔(水,模拟)

汉诺塔的非递归实现(借助堆栈模拟递归)

设计递归函数模拟汉诺塔游戏