Problem E
Editing a Book
You have n equal-length paragraphs numbered 1 to n. Now you want to arrange them in the order of 1, 2, …, n. With the help of a clipboard, you can easily do this: Ctrl-X (cut) and Ctrl-V (paste) several times. You cannot cut twice before pasting, but you can cut several contiguous paragraphs at the same time - they’ll be pasted in order.
For example, in order to make {2, 4, 1, 5, 3, 6}, you can cut 1 and paste before 2, then cut 3 and paste before 4. As another example, one copy and paste is enough for {3, 4, 5, 1, 2}. There are two ways to do so: cut {3, 4, 5} and paste after {1, 2}, or cut {1, 2} and paste before {3, 4, 5}.
Input
The input consists of at most 20 test cases. Each case begins with a line containing a single integer n (1 < n < 10), the number of paragraphs. The next line contains a permutation of 1, 2, 3,…, n. The last case is followed by a single zero, which should not be processed.
Output
For each test case, print the case number and the minimal number of cut/paste operations.
等长段落编号1到n。现在你想安排他们的顺序为1、2、……的帮助下,n。一个剪贴板,您可以很容易地做到这一点:Ctrl-X(减少)和ctrl - v(粘贴)好几次了。你不能剪两次粘贴,但你可以同时剪切几个连续的段落。
例如,为了使{ 2、4、1、5、3、6 },可以剪切1和粘贴在2前,然后剪切3和粘贴在4前。另外一个例子,一个复制和粘贴是足够{ 3、4、5、1、2 }。有两种方法可以这样做:剪切{ 3、4、5 } 粘贴在{ 1,2 }后,或剪切{ 1,2 }粘贴 在{ 3、4、5 }之前。
输入
输入包含最多20个测试用例。每个案例始于一行包含一个整数(1 < n < 10),段落的数量。下一行包含一个排列的1、2、3、……,n。最后一个案例是紧随其后的是一个零,它不应该被处理。
输出
为每个测试用例,打印数量和最小数量的剪切/粘贴操作。
Sample Input
6
2 4 1 5 3 6
5
3 4 5 1 2
0
Output for the Sample Input
Case 1: 2
Case 2: 1
Rujia Liu’s Present 2: A Big Contest of Brute Force
Adapted from ACM/ICPC Kanpur Site 2001-2001
我有话说:
这道题虽然数字个数很少,但是后继状态相当多。如果没有很好的剪枝很容易超时。可以提供几种策略:
1只剪切连续的片段,不能破坏已经连续的片段。
2剪切后设[i,j]为剪切的片段。那么要么粘贴在a[i]+1后或者是a[j]+1前。
但是他们不一定正确,如5,4,3,2,1这个序列。
这道题的另一种解法是看作IDA*问题。考虑启发函数。因为移动一次最多只会使三个数放在正确的位置上。证明:
[ ……a] [……b] [……c] [……]
把b段移动到c后。
[ ……a] [……c] [……b] [……]
最多a,b,c三个数到达正确的位置。
所以当d*3+h> maxd *3时可以剪枝。
#include
#include
#include
#include
using namespace std;
const int maxn=9;
int n,a[maxn];
bool is_sorted()
{
for(int i=0;i1;i++)
if(a[i]>=a[i+1])return false;
return true;
}
int h()
{
int cnt=0;
for(int i=0;i1;i++)
{
if(a[i]+1!=a[i+1])cnt++;
}
if(a[n-1]!=n)cnt++;
return cnt;
}
bool dfs(int d,int maxd)
{
if(d*3+h()>maxd*3)return false;
if(is_sorted())return true;
int olda[maxn],b[maxn],cut[maxn];
memcpy(olda,a,sizeof(a));
for(int i=0;ifor(int j=i;jint cnt=0;
for(int k=0;kif(kj)b[cnt++]=a[k];
}
for(int k=0;k<=cnt;k++)
{
int cnt2=0;
for(int p=0;pfor(int p=i;p<=j;p++)a[cnt2++]=olda[p];
for(int p=k;pif(dfs(d+1,maxd))return true;
memcpy(a,olda,sizeof(a));
}
}
}
return false;
}
int solve()
{
if(is_sorted())return 0;
int max_ans=5;//经证明n<=9时,ans<=5
for(int maxd=1;maxdif(dfs(0,maxd))return maxd;
return max_ans;
}
int main()
{
int kase=0;
while(scanf("%d",&n)==1&&n)
{
for(int i=0;iscanf("%d",&a[i]);
printf("Case %d: %d\n",++kase,solve());
}
return 0;
}