• 【编程题目】有两个序列 a,b,大小都为 n,序列元素的值任意整数,无序;(需要回头仔细研究)


    32.(数组、规划)
    有两个序列 a,b,大小都为 n,序列元素的值任意整数,无序;
    要求:通过交换 a,b 中的元素,使[序列 a 元素的和]与[序列 b 元素的和]之间的差最小。
    例如:
    var a=[100,99,98,1,2,3];
    var b=[1,2,3,4,5,40];

    首先,目标一定是先找到n个数字,使得数字和比总和的一半小,但是最接近。

    思路一:开始看这道题跟之前学的动态规划很像,就想用动态规划来解。但是....做不出来........... 必须要选一半的数字让我头都大了。

    思路二:接着想写递归,就是把a, b(各n个)中的数字都放在 c 中,选一半的数字n个那就可以分为:

    1.选入最后一个数字 第2n - 1个,在剩下的数字中选择其他 n - 1个数字

    2.不选入最后一个数字, 在剩下的数字中选择 n个数字

    这样,递归的思路就有了。

    可是在怎么把得到的结果传出来上面我又犯了难,每个数字都是一层层递归选的,怎么传出来啊?? 好了,到这里卡死了......

    void choose(int * c, int len, int N, int sum) //N是要从中挑选几个数字
    {
        static int sumtmax = 0;
        static int sumt = 0;
        static int num = 0;
        if(len < N)
        {
            return;
        }
        if(N == 0)
        {
            if(sumt <= sum/2 && sumt > sumtmax)
            {
                sumtmax = sumt;
            }
            printf("%d : %d  %d
    ", ++num, sumt, sumtmax);
            return;
        }
    
        choose(c, len - 1, N, sum);
    
        sumt += c[len - 1];
        choose(c, len - 1, N - 1, sum);
        sumt -= c[len - 1];
    }
    
    void exchange(int * a, int * b, int len)
    {
        int * c = (int *)malloc(2 * len * sizeof(int));
        int * smaller = (int *)malloc(len * sizeof(int));
        int sum = 0;
        for(int i = 0; i < len; i++)
        {
            c[i] = a[i];
            sum += a[i];
        }
        for(int i = 0; i < len; i++)
        {
            c[i + len] = b[i];
            sum += b[i];
        }
    
        choose(c, len * 2, len, sum);
        
    }

    思路三:和12个人排两列的思路相同。用二进制 用数字i 从0 - (1 << 2 * n)的范围变化, 其二进制中的1,就表示数字选入a, 我们遍历所有的可能找到a中的和最接近总和一半的组合。再另外用一个数字保存最接近时的分布就好了。

    不过这样的写法一个很不好的限制就是int的位数是有限的,只有64位,也就是说n大于32时我的方法就失效了

    /*
    32.(数组、规划)
    有两个序列 a,b,大小都为 n,序列元素的值任意整数,无序;
    要求:通过交换 a,b 中的元素,使[序列 a 元素的和]与[序列 b 元素的和]之间的差最小。
    例如:  
    var a=[100,99,98,1,2,3];
    var b=[1,2,3,4,5,40];
    */
    
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    
    int bit_c(int n) //统计n的二进制表达中有几个1
    {
        int result = 0;
        for(; n; n &= n-1, result++);
        return result;
    }
    
    void exchange2(int * a, int * b, int len)
    {
        int * c = (int *)malloc(2 * len * sizeof(int));
        int * smaller = (int *)malloc(len * sizeof(int));
        int sum = 0;
        for(int i = 0; i < len; i++)
        {
            c[i] = a[i];
            sum += a[i];
        }
        for(int i = 0; i < len; i++)
        {
            c[i + len] = b[i];
            sum += b[i];
        }
    
        int maxsumh = 0;
        int mask = 0;
        for(int i = 0; i < (1 << len * 2); i++)
        {
            if(bit_c(i) == len)
            {
                int sumhalf = 0;
                for(int j = 0; j < len * 2; j++)
                {
                    if(((i >> j) & 1) == 1)
                    {
                        sumhalf += c[j];
                    }
                }
                if(sumhalf <= sum / 2 && sumhalf > maxsumh)
                {
                    maxsumh = sumhalf;
                    mask = i;
                }
            }
        }
    
        int ai = 0, bi = 0;
        for(int j = 0; j < len * 2; j++)
        {
            if(((mask >> j) & 1) == 1)
            {
                a[ai++] = c[j];
            }
            else
            {
                b[bi++] = c[j];
            }
        }
    
        printf("最小差值为:%d", sum - 2 * maxsumh);
    
        free(c);
        
    }
    
    int main()
    {
        int a[5] = {1,2,3,4,5};
        int b[5] = {30, 40, 50, 60, 23};
        exchange2(a, b, 5);
        return 0;
    }

    网上有各种解法:

    http://blog.csdn.net/tianshuai1111/article/details/7479767 中提出了两种。

    但其中一种被http://blog.csdn.net/cwqbuptcwqbupt/article/details/7521733 用反例否决了。

    http://blog.csdn.net/ljsspace/article/details/6434621# 中用到了回溯法 但评论中说存在问题 我还没仔细看

  • 相关阅读:
    Linux 切换用户
    Java之.jdk安装-Linux
    Java之.jdk安装-Windows
    java注解生成xml和包含CDATA问题
    Spring学习—生成图片验证码
    java学习——java按值传递和按址传递
    温水中被煮熟的程序员-人生的思考
    mysql操作sql的小技巧
    java的classLoader分析与jettty的WebAppClassLoader
    深入Spring:自定义事务管理
  • 原文地址:https://www.cnblogs.com/dplearning/p/3903486.html
Copyright © 2020-2023  润新知