zoukankan      html  css  js  c++  java
  • AOJ-743-多重部分和问题

    Description
    有n种不同大小的数字,每种各个。判断是否可以从这些数字之中选出若干使它们的和恰好为K。

    Input
    首先是一个正整数T(1<=T<=100)
    接下来是T组数据
    每组数据第一行是一个正整数n(1<=n<=100),表示有n种不同大小的数字
    第二行是n个不同大小的正整数ai(1<=ai<=100000)
    第三行是n个正整数mi(1<=mi<=100000),表示每种数字有mi个
    第四行是一个正整数K(1<=K<=100000)

    Output
    对于每组数据,如果能从这些数字中选出若干使它们的和恰好为K,则输出“Yes”,否则输出“No”,每个输出单独占一行

    Sample Input
    2
    3
    3 5 8
    3 2 2
    17
    2
    1 2
    1 1
    4

    Sample Output
    Yes
    No

    Source
    安徽省2015年“京胜杯”大学生程序设计竞赛

    —————————并不华丽的分界线————————————
    很明显,这是一个入门的多重背包问题。
    对于背包问题,想要了解的更多的可以去看看背包九讲,或者是2009年国家集训队论文《浅谈几类背包问题》(作者是浙江省温州中学徐持衡)
    对于这个背包问题,很明显只需要使用普通的解法就可以了,也就是把每种物品的数量分成1,2,4,8…..V[i] - 2^n -1(V[i]表示第i个物品的数量,其价值为A[i])就可以了。
    在做多重背包时,第一个想法必然是把多重背包转化为01背包,但是这个时候,它的时间复杂度就会比较高,可能能达到O(NM∑Vi),那么这个算法就不是很可取了,但是如果考虑把V[i]化成V[i] = 1 + 2 + 4 + …. + V[i]-2^n-1且每个物品的价值也以此来改变,那么其时间复杂度可以大大优化。当然,如果想要获得更大的优化,可以使用单调队列优化。
    所以这道题就非常容易了,代码如下:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 100010;
    int a[maxn];
    int m[maxn];
    int f[maxn];
    
    bool judge(int n, int k){
        for(int i = 0; i <= k; i++){
            f[i] = 0;
        }
        for(int i = 0; i < n; i++){
            int t = 1;
            while(m[i] > 0){
                if(t > m[i]){
                    t = m[i];
                }
                m[i] = m[i] - t;
    
                for(int j = k; j >= a[i] * t; j--){
                    f[j] = max(f[j], f[j - t * a[i]] + t * a[i]);
                }
                t *= 2;
            }
        }
        for(int j = 0; j <= k; j++){
            if(f[j] == k)
                return true;
        }
        return false;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            int n, k;
            scanf("%d",&n);
            for(int i = 0; i < n; i++){
                scanf("%d",&a[i]);
            }
            for(int i = 0; i < n; i++){
                scanf("%d",&m[i]);
            }
            scanf("%d",&k);
            if(judge(n, k)){
                printf("Yes
    ");
            }else{
                printf("No
    ");
            }
        }
        return 0;
    }

    本人渣渣,如有哪里错误,请各位大牛指正。

  • 相关阅读:
    CS224n, lec 10, NMT & Seq2Seq Attn
    CS231n笔记 Lecture 11, Detection and Segmentation
    CS231n笔记 Lecture 10, Recurrent Neural Networks
    CS231n笔记 Lecture 9, CNN Architectures
    CS231n笔记 Lecture 8, Deep Learning Software
    CS231n笔记 Lecture 7, Training Neural Networks, Part 2
    pytorch坑点排雷
    Sorry, Ubuntu 17.10 has experienced an internal error
    VSCode配置python插件
    tmux配置与使用
  • 原文地址:https://www.cnblogs.com/wiklvrain/p/8179499.html
Copyright © 2011-2022 走看看