zoukankan      html  css  js  c++  java
  • luogu2744 量取牛奶

    题目大意

      给出一个整数集合$A$,总数$N$,规定一个整数序列${a_n}, forall i, a_iin A$满足条件:存在一个正整数序列${k_n}$,使得$sum_{i=1}^n a_i k_i = S$。求$n$最小值且字典序最小的$a_i$。

    题解

    错误解法

      令$f(j)$表示使得$sum_{i=1}^m a_i k_i = j$的最小的$m$的值,令$i$为第几个$A$中的整数,则刷表递推式方式为UpdateMin$(f(j+A_i k),f(j)+1)$。这时我想,如果把$A$中的元素从小到大排序,只有能将以后的状态更新成最小时才更新答案,那么记录到的决策必然就是字典序最小的了。这样就错了,因为如果组成$j_1+K_1 A_{i_1}=j_2+K_2A_{i_2}=S$,$i_1 < i_2$,我们无法证明组成$j_1$的元素的字典序就比$j_2$的小。反例很难容易得出。

    正确解法

      对每个$n$枚举$a_i$为$N$内的组合,然后用完全背包判断选择的组合是否满足条件即可。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    
    const int MAX_OBJ = 150, MAX_V = 21000;
    int TotObj, TotV;
    int Vs[MAX_OBJ];
    vector<int> Ans;
    
    bool DP(int *_vs)
    {
        static bool f[MAX_V], vis[MAX_V];
        memset(f, false, sizeof(f));
        f[0] = true;
        for (int i = 1; i <= TotObj; i++)
        {
        	if (!_vs[i])
        		continue;
            memset(vis, false, sizeof(vis));
            for (int j = 0; j <= TotV; j++)
            {
                if (f[j] && !vis[j])
                {
                    for (int k = 1; k <= (TotV - j) / _vs[i]; k++)
                    {
                    	f[j + k * _vs[i]] = true;
                    }
                }
            }
        }
        return f[TotV];
    }
    
    void JudgeAns(vector<int>& chosen)
    {
        static int _vs[MAX_OBJ];
        memset(_vs, 0, sizeof(_vs));
        for (unsigned int i = 0; i < chosen.size(); i++)
            _vs[chosen[i]] = Vs[chosen[i]];
        if (DP(_vs))
            Ans = chosen;
    }
    
    void Comb(vector<int>& chosen, int n, int m, int begin, void (*doSth)(vector<int>&))
    {
        if (n - begin + 1 < m - chosen.size())
            return;
        if (chosen.size() == m)
        {
            doSth(chosen);
            return;
        }
        for (int i = begin; i <= n; i++)
        {
            if (Ans.size())
                return;
            chosen.push_back(i);
            Comb(chosen, n, m, i + 1, doSth);
            chosen.pop_back();
        }
    }
    
    int main()
    {
        scanf("%d%d", &TotV, &TotObj);
        for (int i = 1; i <= TotObj; i++)
            scanf("%d", Vs + i);
        sort(Vs + 1, Vs + TotObj);
        vector<int> chosen;
        for (int i = 1; i <= TotObj; i++)
        {
            Comb(chosen, TotObj, i, 1, JudgeAns);
            if (Ans.size())
                break;
        }
        printf("%d ", (int)Ans.size());
        for (unsigned int i = 0; i < Ans.size(); i++)
            printf("%d ", Vs[Ans[i]]);
        printf("
    ");
        return 0;
    }
    

      

  • 相关阅读:
    哈希表(python)
    双端循环列表实现栈(python)
    链表实现队列(python)
    循环双端链表(python)
    单链表(python)
    LRU(最近最少使用)(python实现)
    Ajax在Django框架中简单应用2
    图书管理系统增删改查
    Jenkins接入LDAP
    安装python3.6
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9652563.html
Copyright © 2011-2022 走看看