Uva 1611 Crane

Thinking about it:

  对于一个长度为N的序列,最大的数字为N,那么如果要将它放回到第N个位置,那么最多需要2步。

 

  先用例子简单证明一下:

    假设序列:1 2 3 6 5 4,当前最大数为6,需要和4交换位置,那么可以看作:* * * 6 * 4,因为6和4之间有一个数,而6之前有三个数,那么可以之间把6之后的部分,与6(包括)之前的     等长部分交换,可得 : 1 2 5 4 3 6,此时只需要一步,即可。   若如果,6之前的数 小于 6与4之间的数呢,如 1 6 2 3 4 5 ? 那么可以把4之前的整个一部分进行交换,可得:2 3 1 6 4 5,此时有可以从复刚才那一步了。

     你可能会问,为什么交换一半就一定能重复上一步能。其实这是可以证明的,假设 6 之前的数总共有 x 个, 而 6 与 4 之前的数有 y 个,且 x < y,假设交换一半,那么6 之前的数有(x + (x+y+1)/2)个数,而6 和 4 之间的数为 ( (x+y+1)/2 - x - 1),虽然可能会因为x+y+1的奇偶性产生一点变化,但相对大小已经确定,也就是变换后 6 之前的数项 仍旧会大于等于 6和4之间的数项

  

  综上可得:

    对于一个长度序列为N的序列可以依次将N,N-1,N-2,... ,3, 2 放回原处,而每一次放置最多两步,所以总共最多2N步。

 

Reference:

  1.《算法竞赛入门经典(第2版)》

 

PS:

  刚开始用冒泡的思想,交换邻近的数,但需要N^2次交换,必然不符提议。后来想到,要将当前最大的数放到最后,不一定需要通过交换邻近的两个数,可以试着在一步操作时,交换更多的数,这样对于要交换的数来说,移动的距离大了,但操作只是计入一步而已。

 

Code:

/**
 * AC @ Sep 16th 2015
 * Run Time : 0.322s
 */
#include <bits/stdc++.h>

using namespace std;

typedef std::pair<int, int> Node;
vector<int> crane_vec;
vector< Node > ans;
int N;

int search(vector<int> &lst, int value) {
    for (vector<int>::iterator it = lst.begin(); it != lst.end(); ++it) {
        if (*it == value) {
            return it - lst.begin();
        }
    }
    return -1;
}

void read() {
    crane_vec.clear();
    ans.clear();
    // ensure that the first element is counted from 1
    ans.push_back(make_pair(0, 0));
    crane_vec.push_back(-1);

    cin >> N;
    int tmp;
    for (int i = 0; i < N; ++i) {
        cin >> tmp;
        crane_vec.push_back(tmp);
    }
}

// swap from start to end as the problem tells
void swap(int start, int end) {
    ans.push_back(make_pair(start, end));
    int mid = (start + end) >> 1;
    for (int i = start; i <= mid; ++i) {
        int t = crane_vec[i];
        crane_vec[i] = crane_vec[mid  + 1 + i - start];
        crane_vec[mid  + 1 + i - start] = t;
    }
}

void done() {
    int target;
    while(N > 1) {
        if (crane_vec[N] != N) {
            target = search(crane_vec, N);
            // fr : the useless element(s) before N
            // bk : the useless element(s) between  N and the last element in crane_vec
            int fr = target - 1;
            int bk = N - target - 1;
            if (fr < bk) {
                // odd or even : the seap operation must need even elements
                swap(1, N & 1 ? N - 1 : N - 2);

                target = search(crane_vec, N);
                fr = target - 1;
                bk = N - 1 - target;
            }
            swap(N - 2 * bk - 1, N);
        }
        N --;
    }
}

void out() {
    cout << ans.size() - 1<< endl;
    for (vector< Node >::iterator it = ans.begin() + 1; it != ans.end(); ++it) {
        cout << it->first << " " << it->second << endl;
    }
}

void work() {
    read();
    done();
    out();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin >> T;
    while (T --) {
        work();
    }
    return 0;
}

  

 

posted @ 2015-09-16 21:25  Emerald  阅读(259)  评论(0编辑  收藏  举报