题目描述
题解
这是一道构造题,目标是排序可以用归并排序来解。
按照归并排序的方法做就行了,但是要注意一些细节:
1、每次归并排序的时候都要保证序列是原来的顺序,所以不能直接挪,而要用另一个柱子来当中转站。
2、每次递归完成之后要将所有的盘子挪到刚开始放的地方。这一步也需要用一个中转站。
即不能破环归并排序本身的性质,挪的过程中注意中转站的运用即可。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int max_n=1e4+5;
int n,a[max_n],b[max_n],num;
struct hp{int x,y;}step[1000005];
inline void mergesort(int l,int r,int from,int now)
{
int mid=(l+r)>>1;
if (l==r) return;
int nxt,other;
if (now==1)
{
nxt=2; other=3;
for (int i=l;i<=mid;++i)
step[++num].x=1,step[num].y=3;
for (int i=l;i<=mid;++i)
step[++num].x=3,step[num].y=2;
}
else if (now==2)
{
nxt=1; other=3;
for (int i=l;i<=mid;++i)
step[++num].x=2,step[num].y=3;
for (int i=l;i<=mid;++i)
step[++num].x=3,step[num].y=1;
}
else if (now==3)
{
nxt=1; other=2;
for (int i=l;i<=mid;++i)
step[++num].x=3,step[num].y=2;
for (int i=l;i<=mid;++i)
step[++num].x=2,step[num].y=1;
}
mergesort(l,mid,nxt,nxt);
mergesort(mid+1,r,now,now);
int i=l,j=mid+1,k=l;
while (i<=mid&&j<=r)
{
if (a[i]<=a[j])
{
b[k++]=a[i++];
step[++num].x=nxt; step[num].y=other;
}
else
{
b[k++]=a[j++];
step[++num].x=now; step[num].y=other;
}
}
while (i<=mid)
{
b[k++]=a[i++];
step[++num].x=nxt; step[num].y=other;
}
while (j<=r)
{
b[k++]=a[j++];
step[++num].x=now; step[num].y=other;
}
for (int i=l;i<=r;++i)
{
step[++num].x=other; step[num].y=from;
}
for (int i=l;i<=r;++i) a[i]=b[i];
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
mergesort(1,n,1,1);
printf("%d\n",num);
for (int i=1;i<=num;++i)
printf("%d %d\n",step[i].x,step[i].y);
}