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\n", 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;
}

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

/*
3
1 3
0
2 2 1
2 2 1
0
1 3
*/

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

#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 += "\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);
    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
*/

原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9795411.html

时间: 2024-10-27 19:55:49

P1242 新汉诺塔(搜索+模拟退火)的相关文章

P1242 新汉诺塔

这道题加深了hanio的理解 如果我们要移动第n个盘子.那么就是说,n+1以后(包括n+1)的盘子都已经到位了 #include<iostream> #include<cstdio> using namespace std; int no[4]; int ai[4]; int aim[50]; int pla[50]; long long ans; void move(int num,int f,int t) { ans+=1; printf("move %d from

UVa10795 A Different Task (新汉诺塔问题)

链接:http://acm.hust.edu.cn/vjudge/problem/34699分析:考虑编号最大的盘子,如果这个盘子的初始局面和目标局面中都是位于同一根柱子上,那么根本不需要移动它,因为没有其它的盘子编号比它大,说明它所在的这根柱子中它在最底层,也不会影响其它盘子的移动.这样,我们可以在初始局面和目标局面中,找出所在柱子不同的盘子中编号最大的一个,设为k,那么k必须移动.我们可以设想移动k之间的一瞬间柱子上的情况,假设盘子k要从柱子1移到柱子2,由于编号比k大的盘子都放好了不需要移

UVA 10795 A Different Task(新汉诺塔问题)

 题目大意:就是普通的汉诺塔问题,给出n,表示说有n个大小不同的碟子,然后再给出每个碟子的初始位置和目标位置,要求计算出最少的步数使得每个碟子都移动到它的目标位置. 思路:考虑编号最大的盘子,如果它在初始位置和目标局面在同一根柱子上,那么我们不需要移动它. 由于盘子的移动是可逆的,根据对称性,我们只需要求出初始局面和目标局面移动形成的参考局面的步数之和,然后加一即可. 我们可以写一个函数f(P, i, final)表示已知各盘子初始编号为P,把1,2,3....i移动到final柱子上所需要

大白_uva10795_新汉诺塔

题意:给出所有盘子的初态和终态,问最少多少步能从初态走到终态,其余规则和老汉诺塔一样. 思路: 若要把当前最大的盘子m从1移动到3,那么首先必须把剩下的所有盘子1~m-1放到2上,然后把m放到3上. 现在要解决怎样将一个状态s0转移到s(1~k全部放到一个盘子c上面),要放k,那么必须先有一个相似的状态s0,:1~k-1放到一个盘子,然后转移k,然后将1~k-1再放到k上面(原始的汉若塔问题,步数为2^(1<<(k-1)) ),可以看出解决s0和解决s是一个问题,这就得到了状态转移方程了,可以

UVa新汉诺塔问题(A Different Task,Uva 10795)

主要需要理递归函数计算 1 #define MAXN 60+10 2 3 #include<iostream> 4 using namespace std; 5 6 int n,k,S[MAXN],F[MAXN]; 7 8 long long f(int *P,int i,int final) 9 { 10 if(i==0) return 0; 11 if(P[i]==final) return f(P,i-1,final); 12 return f(P,i-1,6-P[i]-final)+(

UVA 10795 新汉诺塔问题

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1736 http://7xjob4.com1.z0.glb.clouddn.com/c2dd6437bf7bef120bf27475f3097822 题意:至少多少步将当前局面状态移动后到指定局面状态 思路:先考虑最大的那个盘子,将它移到最终位置,那么参考局面为其中一个柱子为空,一个为只有最

新汉诺塔

题目描述 设有n个大小不等的中空圆盘,按从小到大的顺序从1到n编号.将这n个圆盘任意的迭套在三根立柱上,立柱的编号分别为A.B.C,这个状态称为初始状态. 现在要求找到一种步数最少的移动方案,使得从初始状态转变为目标状态. 移动时有如下要求: ·一次只能移一个盘: ·不允许把大盘移到小盘上面. 输入输出格式 输入格式: 文件第一行是状态中圆盘总数: 第二到第四行分别是初始状态中A.B.C柱上圆盘的个数和从上到下每个圆盘的编号: 第五到第七行分别是目标状态中A.B.C柱上圆盘的个数和从上到下每个圆

【汉诺塔问题】UVa 10795 - A Different Task

[经典汉诺塔问题] 汉诺(Hanoi)塔问题:古代有一个梵塔,塔内有三个座A.B.C,A座上有64个盘子,盘子大小不等,大的在下,小的在上.有一个和尚想把这64个盘子从A座移到B座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,小盘在上.在移动过程中可以利用B座,要求打印移动的步骤.如果只有一个盘子,则不需要利用B座,直接将盘子从A移动到C. 如果有2个盘子,可以先将盘子1上的盘子2移动到B:将盘子1移动到c:将盘子2移动到c.这说明了:可以借助B将2个盘子从A移

韩顺平_PHP程序员玩转算法公开课(第一季)01_算法重要性_五子棋算法_汉诺塔_回溯算法_学习笔记_源代码图解_PPT文档整理

文西马龙:http://blog.csdn.net/wenximalong/ 课程说明:算法是程序的灵魂,为什么有些网站能够在高并发,和海量吞吐情况下依然坚如磐石,大家可能会说: 网站使用了服务器集群技术.数据库读写分离和缓存技术(比如memcahced和redis等),那如果我再深入的问一句,这些优化技术又是怎样被那些天才的技术高手设计出来的呢? 我在上大学的时候就在想,究竟是什么让不同的人写出的代码从功能看是一样的,但从运行效率上却有天壤之别, 就拿以前在软件公司工作的实际经历来说吧, 我是