题目链接

题意:

有三根编号为\((1, \, 2, \, 3)\)的柱子,然后第一根柱子上有编号为\(1 \sim n(n \leq 10000)\)的盘子,从上到下第\(i\)个盘子的编号是\(A_i\),其他两根柱子是空的。

你可以进行一种操作x y,表示将第\(x\)根柱子最上面的盘子放到第\(y\)根柱子的最上面去。

输出不超过\(10^6\)次操作,使得最终所有的盘子都在同一根柱子(柱子的编号不限)上而且从上到下编号是递增的。

分析:

首先很容易想到一个\(O(n^2)\)的做法:

就是每次遇到不是\(n\)的盘子的时候就扔到柱子\(3\)上去,否则就扔到柱子\(2\)上去。

然后重复这一过程,在\(n-1\)号盘子所在的柱子上,遇到不是\(n-1\)的就扔到其他柱子上,遇到\(n-1\)就扔到柱子\(2\),也就是\(n\)号盘子的上面。

然后有一个\(O(n^{\frac{3}{2}})\)的做法。是基于平方分割的思想,每次取出\(\sqrt{n}\)个编号最大的盘子,然后暴力用\(O((\sqrt{n})^2)=O(n)\)次操作将其排序。

最后是\(O(nlogn)\)的做法:

这种做法是基于分治的思想,和快排的思路一模一样:先分解问题然后再合并问题。

我们规定从上到下递增的是顺序,从上到下递减的是逆序。

分:

对于某个柱子上乱序的区间\([l, \, r]\),如果我们要将它顺序排序,我们可以将\([l, \, mid]\)中的盘子和\([mid+1, \, r]\)中的盘子分别扔到其他两根柱子上。

然后对这两个根柱子上的盘子逆序排序。

合:

左右区间逆序排好序后然后按照从大到小的顺序再放回原来的柱子上,使得整个\([l, \, r]\)是顺序的。

对\([l, \, mid]\)和\([mid+1, \, r]\)这两个区间逆序排序,这样问题的规模就减小了一半。

相反地,如果要对一个区间逆序排序,就要先对它的左右区间顺序排序,然后合并。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std; const int maxn = 10000 + 10;
int n;
int cnt[3], t[3][maxn];
int lft[] = { 1, 0, 0 };
int rgh[] = { 2, 2, 1 }; void op(int i, int j) {
printf("%d %d\n", i + 1, j + 1);
t[j][cnt[j]] = t[i][cnt[i]-1];
cnt[j]++; cnt[i]--;
} void solve(int cur, int l, int r, bool inv) {
if(l == r) return;
int mid = (l + r) / 2;
for(int i = 1; i <= r-l+1; i++) {
if(t[cur][cnt[cur]-1] <= mid) op(cur, lft[cur]);
else op(cur, rgh[cur]);
}
solve(lft[cur], l, mid, !inv);
solve(rgh[cur], mid+1, r, !inv);
if(!inv) {
for(int i = mid + 1; i <= r; i++) op(rgh[cur], cur);
for(int i = l; i <= mid; i++) op(lft[cur], cur);
} else {
for(int i = l; i <= mid; i++) op(lft[cur], cur);
for(int i = mid + 1; i <= r; i++) op(rgh[cur], cur);
}
} int ans; void dfs(int t) {
if(t == 1) return;
ans += t * 2;
dfs(t / 2);
dfs(t - t / 2);
} int main()
{
scanf("%d", &n);
cnt[0] = n;
for(int i = n-1; i >= 0; i--) scanf("%d", &t[0][i]); ans = 0;
dfs(n);
printf("%d\n", ans);
solve(0, 1, n, false); return 0;
}

UOJ 152 汉诺塔 分治的更多相关文章

  1. [UOJ #167]【UR #11】元旦老人与汉诺塔

    题目大意:给你一个有$n$个盘子的汉诺塔状态$S$,问有多少种不同的操作方法,使得可以在$m$步以内到达状态$T$.$n,m\leqslant100$ 题解:首先可以知道的是,一个状态最多可以转移到其 ...

  2. 算法笔记_013:汉诺塔问题(Java递归法和非递归法)

    目录 1 问题描述 2 解决方案  2.1 递归法 2.2 非递归法 1 问题描述 Simulate the movement of the Towers of Hanoi Puzzle; Bonus ...

  3. C#递归解决汉诺塔问题(Hanoi)

    using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace MyExamp ...

  4. 数据结构0103汉诺塔&八皇后

    主要是从汉诺塔及八皇后问题体会递归算法. 汉诺塔: #include <stdio.h> void move(int n, char x,char y, char z){ if(1==n) ...

  5. Conquer and Divide经典例子之汉诺塔问题

    递归是许多经典算法的backbone, 是一种常用的高效的编程策略.简单的几行代码就能把一团遭的问题迎刃而解.这篇博客主要通过解决汉诺塔问题来理解递归的精髓. 汉诺塔问题简介: 在印度,有这么一个古老 ...

  6. 几年前做家教写的C教程(之四专讲了指针与汉诺塔问题)

    C语言学习宝典(4) 指针:可以有效的表示复杂的数据结构,能动态的分配动态空间,方便的使用字符串,有效的使用数组,能直接处理内存单元 不掌握指针就没有掌握C语言的精华 地址:系统为每一个变量分配一个内 ...

  7. python实现汉诺塔

    经典递归算法汉诺塔分析: 当A柱子只有1个盘子,直接A --> C 当A柱子上有3个盘子,A上第一个盘子 --> B, A上最后一个盘子 --> C, B上所有盘子(1个) --&g ...

  8. fzu1036四塔问题(汉诺塔问题拓展)

    #include<iostream> #include<cstdio> #include<cmath> using namespace std; ]; int ru ...

  9. 1019: [SHOI2008]汉诺塔

    1019: [SHOI2008]汉诺塔 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1495  Solved: 916[Submit][Status] ...

随机推荐

  1. [转]Todd.log - a place to keep my thoughts on programming 分布式架构中的幂等性

    Todd.log - a place to keep my thoughts on programming 理解HTTP幂等性 基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式. ...

  2. 第一天课程-html基础

    一.课程内容: 1.安装需要的软件 安装了三个软件:Adobe Dreamweaver,EmEditor,FSCapture.分别是前端开发软件.功能强大的文本编辑器,截图录屏软件 2.了解文件格式. ...

  3. mui对话框、表单

    1.mui.alert() 普通提醒参数 1.message Type: String 提示对话框上显示的内容 2.title Type: String 提示对话框上显示的标题 3.btnValue ...

  4. PHP超全局变量、魔术变量和魔术方法

    PHP超全局变量 $_GET 通过get方式传递的值(通过 URL 参数传递给当前脚本的变量的数组.) $_POST 通过post形式传递的值(当 HTTP POST 请求的 Content-Type ...

  5. Sqoop基础学习(1)

    1. Sqoop的导入过程 在开始导入之前,Sqoop会通过JDBC来获得所需要的数据库元数据 1.导入表的列名.数据类型等: 2.接着这些数据库的数据类型(varchar.number等)会把映射成 ...

  6. 【selenium学习笔记一】python + selenium定位页面元素的办法。

    1.什么是Selenium,为什么web测试,大家都用它? Selenium设计初衷就是为web项目的验收测试再开发.内核使用的是javaScript语言编写,几乎支持所以能运行javaScript的 ...

  7. POJ 3252 Round Numbers (区间DP,基础)

    题意: 统计区间[L,R]有多少个数,其二进制表示法中的0的个数不少于1的个数?(不允许前缀0) 思路: 状态表示为 [当前第几位][总位数][1的个数],最后判断一下1的个数是否满足条件,要注意前导 ...

  8. codeforces Gym 100286H Hell on the Markets

    紫书上面的题,队友做的,WA了freopen..爆了int... UVA 1614 - Hell on the Markets 奇怪的股市(贪心,结论)

  9. [web开发] Vue+Spring Boot 上海大学预约系统开发记录

    前端界面 使用Quasar将组件都排好,用好css. Quasar 入门 # 确保你在全局安装了vue-cli # Node.js> = 8.9.0是必需的. $ npm install -g ...

  10. 连接惠普打印机(通过WIFI)

    第一步 找到打印机型号 第二步 到惠普官方网站下载对应驱动 第三步 安装驱动 第四步 安装驱动后选择WIFI连接(IP在打印机显示屏幕上显示,如果输入打印机屏幕IP连接失败:需要获取打印机真正的IP地 ...