这个题做起来特别无语,发现自己一些正常的模拟 *** 作都需要联系
给定 n 本书,编号为 1∼n。
在初始状态下,书是任意排列的。
在每一次 *** 作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。
我们的目标状态是把书按照 1∼n 的顺序依次排列。
求最少需要多少次 *** 作。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据包含两行,第一行为整数 n,表示书的数量。
第二行为 n 个整数,表示 1∼n的一种任意排列。
同行数之间用空格隔开。
输出格式
每组数据输出一个最少 *** 作次数。
如果最少 *** 作次数大于或等于 5 次,则输出 5 or more
。
每个结果占一行。
数据范围
1≤n≤15
输入样例:
3
6
1 3 4 6 2 5
5
5 4 3 2 1
10
6 8 5 3 4 7 2 9 1 10
输出样例:
2
3
5 or more
代码:
#include
#include
using namespace std;
const int N=16;
int q[N];
int g[6][N];
int n;
int f()
{
int tot=0;//tot用于记住每个数后缀出现错误的数
for(int i=1;i<=n-1;i++)
if(q[i]+1!=q[i+1])
tot++;
return (tot+2)/3;//因此每次交换只能改变三个后缀(假设每次都能正确改回三个)
}
bool panduan()
{
for(int i=1;i<=n;i++)
if(q[i]!=i)
return false;
return true;
}
bool dfs(int u,int depth)
{
if(u+f()>depth)return false;//如果最优情况下,交换的已经次数都大于depth的话,直接返回false
if(panduan())return true;//找到解后返回
for(int len=1;len
{
int r=qi1+len;
for(int wai=r;wai<=n;wai++)
{
memcpy(g[u],q,sizeof q);
int i,j;//i用于记住每次对接的起点,j表示每次对接的长度。注意!!!
//将某个块砍掉在接起来,一定要记住每次对接的末尾
for(i=qi1,j=r;j<=wai;i++,j++)q[i]=g[u][j];
for(j=qi1;j<=qi1+len-1;i++,j++)q[i]=g[u][j];
if(dfs(u+1,depth)){
return true;
}
memcpy(q,g[u],sizeof g[u]);
}
}
return false;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&q[i]);
int depth=0;
while(depth<=5&&!dfs(0,depth))
depth++;
if(depth<5)
printf("%d\n",depth);
else
printf("5 or more");
}
return 0;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)