题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5500
思路:问题等价为,一个1~n组成的序列,每次从中取出一个数,插到最前面,用最少的步骤使序列变为升序。其实在整个操作过程中,我们只需要保持相对顺序即可。每次操作保证pos[i - 1] < pos[i],即:i - 1出现在i的前面。如:首先检查n - 1是否出现在n前面,不是的话将n - 1移至最前面,是的话则继续检查n - 2和n - 1,如此重复检查直到n - 1对相邻的数都检查完毕。则有:pos[1] < pos[2] < pos[3] < …… < pos[n - 1] < pos[n],则整个序列已经有序。
所以处理方法为:最大的数n不动,然后检查n - 1,若n - 1在n之后,则要将n - 1移至最前面,一直处理到1。下面证明贪心策略的正确性。假设现在处理到i,且pos[i - 1] > pos[i],按照贪心的策略是将i - 1移至序列的最前面。若存在最优的策略是将j < i - 1移至最前面,由于在此后的操作过程中,一定存在一步是将i - 1移到最前面(否则i - 1一直在i的后面),则这一步之后,pos[i - 1] < pos[j], i - 1 > j。要保证序列最后有序,则还需要将j移动至最前面(否则存在逆序对……i - 1,……,j),则最优解的操作步骤不小于贪心策略,矛盾。所以贪心策略已经是最优。
代码如下:
#include <cstdio>
using namespace std;
#define N 25
int idx[N];
int main(){
int tc, n;
scanf("%d", &tc);
while(tc --){
scanf("%d", &n);
int ans = 0;
for(int i = 1; i <= n; ++i){
int x;
scanf("%d", &x);
idx[x] = i;
}
int j = n;
while(j > 1){
if(idx[j - 1] > idx[j])
++ans, idx[j - 1] = 0;
--j;
}
printf("%d\n", ans);
}
return 0;
}