计蒜客 强迫症的吃货

题目如下:

晓萌作为一个营养学专家,吃东西的时候总是要考虑是否能满足他的各种营养物质需求,大家都说他是一个有强迫症的吃货。晓萌知道每种食品中营养物质的含量,请你帮他安排食谱,以保持他获得所需营养物质的同时,吃的食品的种类最少。(营养物质含量为整数,每种食品晓萌只吃一次)。

输入第1行为一个整数V表示晓萌需要的营养物质的种类数(1≤V≤25)。

输入第2行包括用空格分隔开的V个整数,依次表示每种营养物质的需求量(1≤每个整数≤1000)。

输入第3行包括一个整数G表示提供可以给晓萌吃的食品的种类数(1≤G≤15)。

接下来的G行,每行包括用空格分隔开的V个整数,G行中的第i行中V个整数依次表示第i种食品中每种营养物质的含量(1≤每个整数≤1000)。

输出包括空格分隔的多个数,第一个数为必需的最小的食品种数P;后面有P个数,表示所选择的食品编号(按从小到大排列);如果有多个解,输出食品序号最小的(即字典序最小)。

样例输入·

4
100 200 300 400
3
50 50 50 50
200 300 200 300
900 150 389 399

样例输出·

2 1 3

首先说一下思路吧

  • 首先,如果不明白 字典序 含义的话,自行百度
  • 首要条件是 所吃食品种类越少越好,因此直接枚举食品种类为 1、2、3……G 的情况,以减少遍历次数;
  • 在前一思路之下,当前的关键点在于避免出现1、2、3、4 和 1、2、4、3 这样的重复查询(因为吃食品的次序不影响结果),否则会超时;即在递归过程中,若第 cur 种食品已经吃过后,只需要考虑序号在 cur 之后的食品
  • 最后考虑字典序,因为寻找次序是从食品种类为 1 开始递增,并且吃食品的顺序是从序号小的食品开始,因此只要找到第一个满足条件的序列,必然是食品种类最少,并且字典序最小的序列。

附上代码

#include<iostream>
using namespace std;

struct Food{ 
    int f[25];
};

int V,G;
//用来标记吃过的食品 
int map[16]={0};
//记录需要的各种营养物质含量 
int need[25];
//记录当前吃过的食品各营养物质总量 
int prov[25];
Food food[16];
//标记是否已经找到满足要求的食品 
bool m;
//记录当前食品种类 
int kind;

//本层递归要吃第step种食品,前一层递归所吃食品序号为cur 
void dfs(int step,int cur)
{   
    //首先判断是否已经找到满足条件的食品序列 
    m = true;
    for(int k=0;k<V;k++)
    {
        if(prov[k]<need[k])
        {
            m = false;
            break;
        }
    }
    if(m==true)
        return;

    //判断本次递归是否吃够 kind种食品 
    if(step>kind)
        return;

    //这里要明白,在前一层递归,已经吃掉了序号为cur的食品
    //因此,不需要再吃序号在cur之前的食品,否则会出现1、2、3、4和1、2、4、3这样的重复序列 
    for(int i=cur;i<=G;i++)
    {
        if(map[i]==0)
        {
            for(int j=0;j<V;j++)
                prov[j]+=food[i].f[j];
            map[i]=1;
            dfs(step+1,i);
            //若已经找到符合条件的序列,便一层层退出递归 
            if(m==true)
                return;
            //将已吃食品“吐出来” 
            map[i]=0;
            for(int j=0;j<V;j++)
                prov[j]-=food[i].f[j];
        }
    }  
    return;
} 

int main()
{
    cin>>V;
    for(int i=0;i<V;i++)
        cin>>need[i];
    cin>>G;
    for(int i=1;i<=G;i++)
        for(int j=0;j<V;j++)
            cin>>food[i].f[j];

    int i;
    for(i=1;i<=G;i++)
    {
        kind = i;
        if(m==true)
            break;
        dfs(1,1);
    }

    cout<<i-1;
    for(int i=1;i<=G;i++)   
    {
        if(map[i]==1)
            cout<<' '<<i;
    }
    cout<<endl;

    return 0;
}

平时写博客不多,但是刷题过程中难免遇到一些有意思的题目,因此想要将自己的代码分享出来,希望同样做过这道题目的大神可以留言指出代码中的不足,困惑于此题的人也可以留言道出,以此相互学习,共同精进。

思路参考
http://blog.csdn.net/ldw201510803006/article/details/72594317
在参考这篇博客之前困于超时,参考了这篇博客之后根据自己的理解终于通过了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值