hdu5500 Reorder the Books 贪心

来源:互联网 发布:淘宝网店经营技巧 编辑:程序博客网 时间:2024/05/19 23:04

题目链接: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 25int 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;}



0 0