题目描述
农民 John 以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。
给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。
维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。
输入格式
第一行一个整数 vvv,表示需要的维他命的种类数。
第二行 vvv 个整数,表示牛每天需要的每种维他命的最小量。
第三行一个整数 ggg,表示可用来喂牛的饲料的种数。
下面 ggg 行,第 nnn 行表示编号为 nnn 饲料包含的各种维他命的量的多少。
输出格式
输出文件只有一行,包括牛必需的最小的饲料种数 ppp;后面有 ppp 个数,表示所选择的饲料编号(按从小到大排列)。
如果有多个解,输出饲料序号最小的(即字典序最小)。
输入输出样例
输入 #1
4 100 200 300 400 3 50 50 50 50 200 300 200 300 900 150 389 399
输出 #1
2 1 3
说明/提示
【数据范围】
对于 100%100\%100% 的数据,1≤v≤251le v le 251≤v≤25,1≤g≤151le g le 151≤g≤15。
输入的所有整数在 [1,1000][1,1000][1,1000] 范围内。
代码与题解:
#include<iostream> #include<algorithm> #include<string.h> #include<queue> using namespace std; //解题核心思想:题目的最终目的是求最少的饲料种类数(与维他命剂量没关系),因此可以使用bfs算法进行求解 //本题实际上dfs方式求解更简单(只需要dfs(选当前某一饲料)和dfs(不选当前某一饲料即可)) //但关键点在于:最有解中种类数相同的有好几种情况满足,题目要求输出最小的编号 //思路解法一:每次bfs一个节点 直到找到满足的条件为止 记录饲料种数和饲料编号 因此可以使用for循环(但是可能会出现MLE) //思路解法二:把所有的饲料(每一种)当做出发结点,首先全部压入队列(编号小的先压入),一起进行bfs,因此只要第一次找到满足条件的则是满足条件且编号最小的解 int m,n; int mini[26]; //mini[i]代表牛对第i种维他命的最小需求 int si[30][30]; //si[i][j]代表第i种饲料中j维他命的含量 int color[30]={0}; //用于标记哪种饲料被使用过 typedef struct node{ int v[30]; //储存结点的维他命数量的情况 int dis[16]; //储存选择的饲料种类(路径) int num; //选择饲料的种类数量 }N; bool panduan(int *a){ //判断是否满足了最小要求 for(int i=1;i<=m;i++){ if(a[i]<mini[i]) return false; //只要有一种维他命缺少就不满足 } return true; } void bfs(){ queue<N> q; for(int i=1;i<=n;i++){ //n种饲料 因此先生成n个初始结点 N temp; for(int j=1;j<=m;j++){ //m种维他 temp.v[j]=si[i][j]; } temp.dis[0]=i; //注意路径下标从0开始 从0~temp.num-1 temp.num=1; q.push(temp); } while(!q.empty()){ N cur=q.front(); q.pop(); if(panduan(cur.v)){ //找到了立即输出 cout<<cur.num<<" "; for(int i=0;i<cur.num;i++){ cout<<cur.dis[i]<<" "; } return; } //若上述没有找到 则执行下面的遍历其他节点 //节点压入队列的顺序方式为 只压入比刚刚pop出的节点编号大的结点(而且压入的顺序是从小到大 即最开始从pop的结点编号+1开始) //每个初始结点都按照这种只入队编号比pop结点编号大的结点的方式,并且节点最开始也是从1~n的,因此不需要担心会有遗漏的情况出现 //可以理解为:遍历的方向或者入队顺序: //第一个初始点出发(指的是饲料编号):1 2 3 ……n //第二个初始点出发: 2 3 4…… n 以此类推 for(int i=cur.dis[cur.num-1]+1;i<=n;i++){ //这样设置可以保证i一定未走过 N next=cur; for(int j=1;j<=m;j++){ //吃了第i种饲料 所以把对应的维生素加上 next.v[j]+=si[i][j]; } next.dis[next.num]=i; next.num++; q.push(next); } } } int main(){ cin>>m; for(int i=1;i<=m;i++){ cin>>mini[i]; } cin>>n; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>si[i][j]; } } bfs(); return 0; }