USACO 2.1.4 Healthy Holsteins (DFS)

题意:农民JOHN以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。

给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。

维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。

 

思路:搜索每种饲料用了没有,即每层搜索有两种状态:vis[n]=0或vis[n]=1,且不必搜到n=G,只要搜到可供的维生素够用就可以退出(因为要求最少需要的饲料,再往后面走只会多不会少)

 

代码:

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<utility>
#include<queue>
#include<iostream>
#include<algorithm>
const int maxn=30;
using namespace std;

int N;
int G;
int v[maxn];        //每种维生素所需
int jilu[maxn];     //记录搜索中所用过的饲料
int g[maxn][maxn];  //每种饲料能提供多少维生素
int vis[maxn];      //标记每种饲料用没有
int tg[maxn];       //已经提供了的维生素
int minn = 1000000;

void dfs(int n)
{
    int flag = 1;
    for(int i = 0; i < N; i++)
        if(tg[i] < v[i])
        {
            flag = 0;
            break;
        }
    if(flag)
    {
        int ans = 0;
        for(int i =0 ; i < n; i++)
            ans += vis[i];
        if(ans <= minn)
        {
            minn = ans;
            memset(jilu,0,sizeof(jilu));
            for(int i = 0; i < G; i++)
                if(vis[i] == 1)   //绝不能写成vis[i],因为接下来所写的循环中vis[n]可能为2
                    jilu[i] = 1;
        }
        return ;
    }

    if(n == G) return ;

    for(vis[n] = 0; vis[n] <= 1; vis[n]++)
    {
        for (int i = 0; i < N; i++)
            tg[i] += g[n][i]*vis[n];
        dfs(n+1);
        for (int i = 0; i < N; i++)
            tg[i] -= g[n][i]*vis[n];
    }
}


int main()
{
    freopen("holstein.in","r",stdin);
    freopen("holstein.out","w",stdout);
    memset(vis,0,sizeof(vis));
    memset(tg,0,sizeof(tg));
    cin>>N;
    for(int i = 0; i < N; i++)
        cin>>v[i];
    cin>>G;
    for(int i = 0; i < G; i++)
        for(int j = 0; j < N; j++)
            cin>>g[i][j];
    dfs(0);
    cout<<minn;
    for(int i = 0; i < G; i++)
        if(jilu[i])
            cout<<' '<<i+1;
    cout<<endl;
    return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值