11925 - Generating Permutations

来源:互联网 发布:程序员简历 markdown 编辑:程序博客网 时间:2024/05/18 13:05

乍看该题似乎无法下手,但是我们注意到题目所给的操作次数非常大, 而且看它的两个操作,是不是感觉很熟悉? 没错,冒泡排序的复杂度正是O(n^2) 。

该题正是冒泡排序的改进版 。   但是题目要求我们的是将一个1~n的升序序列变成给定序列,这是不好操作的,我们不妨用逆思维来想,由所给序列变成升序排列应该也是可行的。 但是问题在于操作只有两个,是规定好的,那么我们相应的也要变一下,将操作2变成从队列尾拿一个数放到队首 。 操作一并没有规定顺序,所以不需要改变 ,下面我们要做的就是怎么样可以变成升序的 。

我们受到冒泡排序的思想的启发(仅仅比较相邻两个元素,百度百科上有详细的介绍),我们可以不断比较前两个元素,使之成为升序,然后从队尾添加一个元素到队首,重复以上操作 。 这样,最坏的情况是:每个元素都与其他元素比较了大小 。  所以,显然每个元素的顺序也将正确的升序排列 。 

但是值得注意的是:如果按照这个方法,第三组样例会出现错误,陷入了死循环 。。原因很神奇。。我们不妨手动模仿一下,可以发现,在一个循环之中,1和其他三个元素全部比较了一遍,恰好返回原状 !换句话说,1总是在队首,因为它是最小的 。因此,我们将这个特例特判一下,当n在队首时不交换前两个元素 。 至于为什么这样是对的,还是不太明白,明白之后再将详细证明奉上 。

代码如下:

#include<bits/stdc++.h>using namespace std;int n,a[305],ans[100000000];list<int> q;int main() {    while(~scanf("%d",&n)&&n) {        q.clear();        for(int i=0;i<n;i++) {            scanf("%d",&a[i]);            q.push_back(a[i]);        }        list<int> :: iterator it;        list<int> :: iterator io;        bool ok = true; int cnt = 1,rear = 0;        for(int i=0;i<2*n*n;i++) {            ok = true; cnt = 1;            for(it = q.begin();it!=q.end();++it) {                if((*it)!=cnt) { ok = false; break; }                cnt++;            }            if(ok) break;            it = q.begin();            io = it; ++it;            if(*io!=n && *it < *io) { int c = *io; *io = *it; *it = c; ans[rear++] = 1; }            ok = true; cnt = 1;            for(it = q.begin();it!=q.end();++it) {                if((*it)!=cnt) { ok = false; break; }                cnt++;            }            if(ok) break;            int c = q.back();            q.pop_back(); q.push_front(c); ans[rear++] = 2;        }        for(int i=rear-1;i>=0;i--) printf("%d",ans[i]);        printf("\n");    }    return 0;}


0 0
原创粉丝点击