zoukankan      html  css  js  c++  java
  • 计蒜客_三值排序

    问题描述 :

    排序是一种很频繁的计算任务。一个实际的例子是,当我们给某项竞赛的优胜者按金银铜牌排序的时候。在这个任务中可能的值只有三种1,2和3。我们用交换的方法把他排成升序的。
    写一个程序计算出,计算出的一个包括1、2、3三种值的数字序列,排成升序所需的最少交换次数。
    输入第1行为类别的数量N(1≤N≤1000)
    输入第2行到第N+1行,每行包括一个数字(1或2或3)。
    输出包含一行,为排成升序所需的最少交换次数。
    样例输入
    9
    2
    2
    1
    3
    3
    3
    2
    3
    1
    样例输出
    4

    解题思路:

    起初,看到这样的问题,感到无从下手,不过把样例的解题过程搞明白,思路基本就出来了。
    首先,把没有在正确位置的元素表示出来,
    2 1
    2 1
    1 2
    3 2
    3 2
    3 3
    2 3
    3 3
    1 3
    样例原始输入中错误的元素个数为7,正顺序的错误元素个数为0,目标就是通过交换,不断减少错误元素的个数,知道减为0;
    容易知道,如果想达到正确顺序,必须是错误元素和错误元素相互交换,选择恰当时,可减少2个(1放在了2的元素和2放在了1上的元素,例如样例输入中的第二个元素和第三个元素),
    或者1个(1放在了3的元素和2放在了1的元素交换,例如样例中的第一个元素和第5个元素)

    代码如下,主要是两个for循环,时间复杂度为O(n).
    
    
    #include<iostream>
    using namespace std;
    int getNum(int*a, int len) {
        int num[4] = {0};
        //前两个for循环和计数排序过程相近,第一个for循环记录等于1,2和3对应的元素个数,
        //第二个for循环记录通过累加的方式记录小于等于某个元素的总个数,例如
        //第二个for循环以后,如果num[2]=4,也就是说num[1](等于1的个数)+num[2](等于2的个数)=num[2];
        //则(排序以后)值为2的元素下标index满足num[1]<=index<num[2];
        for (int i = 0; i < len; ++i) {
            ++num[a[i]];
        }
        
        for (int i = 1; i < 4; ++i) {
            num[i] += num[i - 1];
        }
        //x31意思是3放在1的位置的个数,x21为2放在1的位置的个数,以下的变量意义相同。
        //以下三个for循环记录相应错误元素的个数。
        int x31 = 0, x21 = 0;
        for (int i = 0; i < num[1]; ++i) {
            if (a[i] == 2) {
                ++x21;
            }
            else if (a[i] == 3) {
                ++x31;
            }
        }
        int x12 = 0, x32 = 0;
        for (int i = num[1]; i < num[2]; ++i) {
            if (a[i] == 1) {
                ++x12;
            }
            else if (a[i] == 3) {
                ++x32;
            }
        }
        int x13 = 0, x23 = 0;
        for (int i = num[2]; i < num[3]; ++i) {
            if (a[i] == 1) {
                ++x13;
            }
            else if (a[i] == 2) {
                ++x23;
            }
        }
        //首先,将x12类型和x21类型(对应的还有x31和x13,x23和x32)相互交换,交换次数为两者较小值,每次交换可以减少两个错误元素的个数。
        int counts = 0;
        if (x12 > x21) {
            counts += x21;
            x12 -= x21;
            x21 = 0;
        }
        else {
            counts += x12;
            x21 -= x12;
            x12 = 0;
        }
        if (x13 > x31) {
            counts += x31;
            x13 -= x31;
            x31 = 0;
        }
        else {
            counts += x13;
            x31 -= x13;
            x13 = 0;
        }
        if (x23 > x32) {
            counts += x32;
            x23 -= x32;
            x32 = 0;
        }
        else {
            counts += x23;
            x32 -= x23;
            x23 = 0;
        }
        //通过推理可知,x13,x32,x21如果三者中有一个不等于零,则三者必然相等,(先将x13和x21交换,剩余x23和x32,两者再次交换,总次数为2*x13)
        //同理还有(x31,x12,x23);
        if (x13 != 0) {
            counts += 2 * x13;
        }
        else if (x31 != 0) {
            counts += 2 * x31;
        }
        return counts;
    }
    void input() {
        int n;
        cin >> n;
        int a[1000];
        for (int i = 0; i < n; ++i)
            cin >> a[i];
        cout << getNum(a, n) << endl;
    }
    int main() {
        input();
    }
    如有不当,欢迎指正 :)
  • 相关阅读:
    django框架——十二
    django框架——十一
    请简述一下你所了解的数据源控件有哪些
    在ASP.NET中,<%= %>和<%# %>有什么区别
    请解释ASP.NET中的web页面与其隐藏类之间的关系
    什么是viewstate,能否禁用?是否所用控件都可以禁用
    WEB控件及HTML服务端控件能否调用客户端方法?如果能,请解释如何调用
    静态类和静态方法的好处
    请写出在ASP.NET中常用的几种页面间传值的方法,并说出它们的特点。
    连接数据库主要有哪几个对象
  • 原文地址:https://www.cnblogs.com/lif323/p/7389636.html
Copyright © 2011-2022 走看看