• SDUT OJ I样(0-1背包问题 【模板】)


    I样

    Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^

    题目描述

    这是个什么问题呢?DP,贪心,数据结构,图论,数论还是计算几何?管他呢,反正胖巨巨都会,虽然胖巨巨走得早。
    现在有n个数Xi,现在你要把这些数分成两组A,B,使得abs(sum(A)-sum(B))尽可能的小,并且每个Xi必须且只能分
    到一组中,每组至少包含一个数字。
    sum()表示计算累加和,abs()表示计算绝对值。

    输入

     输入有多组。对于每组数据:
    第一行输入一个n(1 <= n <= 100),接下来的n行每行一个整数Xi(1 <= Xi <= 50)。

    输出

     对于每组数据,如果你能完成任务输出一个整数代表答案,否则输出-1。

    示例输入

    3
    3
    1
    2
    2
    2
    10

    示例输出

    0
    8
    

      算法分析:此题目开始看上去可以用贪心算法实现,其实不然。对于一些比较坑点的数据,结果就挂了!

       例如前辈给我出的数据:

       5

       10 8 9 5 4      正确结果应该是0,贪心的结果就挂了!

       正确的算法是:如果想让两个分立的数字集合的abs()之差最小,也就是说让两个集合的各自的和尽可能的接近

        (sum(集合a)+sum(集合b))/2.  即使不会完全均分也不要在意,因为我们要用接下来的背包来做,这个背包

        不一定是装满的!

        代码:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <math.h>
    #include <ctype.h>
    #include <algorithm>
    
    using namespace std;
    
    int f[2600];
    
    int main()
    {
        int n;
        int p[150];
        int i, j;
    
        while(scanf("%d", &n)!=EOF)
        {
            int sum=0;
            for(i=0; i<n; i++)
                scanf("%d", &p[i] ), sum+=p[i];
            if(n==1)
            {
                printf("-1
    ");
                continue;
            }
    
            memset(f, 0, sizeof(f));
            int dd=sum;
            sum=sum/2;
            //背包不一定要装满
    
            for(i=0; i<n; i++)
            {
                for(j=sum; j>=p[i]; j--)
                    f[j] = max(f[j], f[j-p[i]]+p[i] );
            }
            dd=dd-f[sum];
            printf("%d
    ", abs(f[sum]-dd) );
    
        }
        return 0;
    }
    
  • 相关阅读:
    .net软件开发工程师面试题
    html笔记
    好用软件
    谷歌插件
    vue笔记
    js笔记
    数组去重
    css全局样式
    css笔记
    vscod插件
  • 原文地址:https://www.cnblogs.com/yspworld/p/4345625.html
Copyright © 2020-2023  润新知