UOJ#152. 【UR #10】汉诺塔

时间:2023-06-26 23:23:14

题目:http://uoj.ac/problem/152

orzKPM。。。

分治,把数字是l~mid的拿出来放在一根柱子上,mid+1~r放在另一根柱子上。如此递归下去,每次递归只是改一下方向,l,r。然后只要处理r-l<=1的情况就可以了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <queue>
#include <cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 1000500
#define ll long long
#define inf int(1e9)
using namespace std;
int ansx[maxn],ansy[maxn],a[][maxn],N[];
int tot;
int read(){
int x=,f=; char ch=getchar();
while (!isdigit(ch)){ if (ch=='-') f=-; ch=getchar();}
while (isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
void move(int x,int y){
ansx[++tot]=x+,ansy[tot]=y+;
a[y][++N[y]]=a[x][N[x]--];
}
void dfs(int x,int l,int r,int dir){
if (l==r) return;
if (r-l<=){
if ((dir==&&a[x][N[x]-]<a[x][N[x]])||(dir==&&a[x][N[x]-]>a[x][N[x]])){
move(x,(x+)%);
move(x,(x+)%);
move((x+)%,x);
move((x+)%,x);
}
return;
}
int mid=(l+r)/; int y=(x+)%,z=(x+)%;
rep(i,l,r) if (a[x][N[x]]<=mid) move(x,y); else move(x,z);
dfs(y,l,mid,-dir);
dfs(z,mid+,r,-dir);
if (dir==){
down(i,r,mid+) move(z,x);
down(i,mid,l) move(y,x);
}
else {
rep(i,l,mid) move(y,x);
rep(i,mid+,r) move(z,x);
}
}
int main(){
int n=read();
down(i,n,) a[][i]=read();
N[]=n;
dfs(,,n,);
printf("%d\n",tot);
rep(i,,tot) printf("%d %d\n",ansx[i],ansy[i]);
return ;
}