zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    LPT算法--时间调度问题
    Java语法学习1
    用JS动态显示文本
    用JS动态创建一个有序表(根据输入添加子列表项)
    邻接表链式结构的实现和顺序结构的实现
    HDU 1242 特殊化带结构体BFS
    POJ 1562深搜判断连体油田个数
    Uva 8道比较水的数论 (练练英语阅读理解)
    HDU 2024 C语言合法标识符(笑)
    再做POJ2406 KMPnext数组的运用
  • 原文地址:https://www.cnblogs.com/Emerald/p/4814600.html
Copyright © 2011-2022 走看看