USACO健康的荷斯坦奶牛(DFS,二进制暴力枚举)

农夫约翰以拥有世界上最健康的奶牛而感到自豪。

奶牛想要保持健康,每天就要补充足量的多种维生素。

约翰为奶牛们准备了多种牛饲料,每种牛饲料中都富含奶牛所需的多种维生素,但是每种维生素的具体含量可能并不相同。

每种牛饲料每天最多只能喂给奶牛们一勺,也就是说每种饲料可以选择不喂给奶牛,或喂给奶牛一勺的量。

现在给定所有饲料的每种维生素的(每勺)具体含量,以及奶牛对于每种维生素的每日最低需求量。

请你求出,保证奶牛各种维生素的每日摄入量达标的情况下,最少需要喂给奶牛多少勺饲料。

数据保证有解。

输入格式
第一行包含一个整数 V,表示共有 V 种所需维生素,编号 1∼V。

第二行包含 V 个不超过 1000 的正整数,其中第 i 个数表示第 i 号维生素的奶牛每日最低需求量。

第三行包含整数 G,表示牛饲料的种类数。

接下来 G 行,每行包含 V 个不超过 1000 的非负整数,其中第 ii 个数表示一种饲料中第 i 号维生素的含量(每勺)。

输出格式
共一行,首先输出一个整数 S,表示最少需要喂给奶牛的饲料数量,接下来输出 S 个升序排列的整数,表示喂给奶牛的饲料的具体编号。

当存在多个解时,输出序列字典序最小的那个解。

数据范围
1≤V≤25,
1≤G≤15
输入样例:
4
100 200 300 400
3
50 50 50 50
200 300 200 300
900 150 389 399
输出样例:
2 1 3
#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

const int N = 25;

int n, m;
//需要的每种维生素量,每一种方案,每种方案求和的结果
int need[N], s[N][N], sum[N];
vector<int> res;

int main()
{
    
    
    cin >> m;
    for(int i = 0; i < m; i++) cin >> need[i];

    cin >> n;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            cin >> s[i][j];

    //枚举每一种方案
    for(int i = 0; i < 1 << n; i++)
    {
    
    
        memset(sum, 0, sizeof sum);

        vector<int> t;
        //检查是否选择了这一行
        for(int j = 0; j < n; j++)
        {
    
    
            if(i >> j & 1)
            {
    
    
                t.push_back(j);
                for(int k = 0; k < m; k++)
                    sum[k] += s[j][k];
            }
        }

        //检查是否满足要求
        bool flag = true;
        for(int j = 0; j < m; j++)
            if(sum[j] < need[j])
            {
    
    
                flag = false;
                break;
            }

        if(flag)
            if(res.empty() || res.size() > t.size() || (res.size() == t.size() && res > t))//最少数量
                res = t;
    }

    cout << res.size() << ' ';
    for(auto t : res) cout << t + 1 << ' ';

    return 0;
}

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

const int N = 25;

int n, m;
int need[N], s[N][N], sum[N];
vector<int> res, t;

//对每一种选出来的方案t进行判断
bool check()
{
    
    
    memset(sum, 0, sizeof sum);
    for(int i = 0; i < m; i++)
    {
    
    
        for(int j = 0; j < t.size(); j++)
            sum[i] += s[t[j]][i];
        if(sum[i] < need[i]) return false;
    }

    if(res.empty() || res.size() > t.size() || (res.size() == t.size() && res > t))
        return true;

    return false;
}

void dfs(int u)
{
    
    
    if(u > n)
    {
    
    
        if(check()) res = t;
        return;
    }

    //选择u这行
    t.push_back(u);
    dfs(u + 1);
    t.pop_back();

    //不选择u这行
    dfs(u + 1);
}

int main()
{
    
    
    cin >> m;
    for(int i = 0; i < m; i++) cin >> need[i];

    cin >> n;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            cin >> s[i][j];

    dfs(0);

    cout << res.size() << ' ';
    for(auto t : res) cout << t + 1 << ' ';

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43738331/article/details/112851356